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
18 changes: 14 additions & 4 deletions src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,25 @@ function createWindow(): void {
}
})

if (saved.isMaximized) win.maximize()
// Full screen and maximize are mutually exclusive; full screen wins so the
// restored geometry matches how the window was left.
if (saved.isFullScreen) win.setFullScreen(true)
else if (saved.isMaximized) win.maximize()

win.on('ready-to-show', () => win.show())

// Remember the window geometry across launches. getNormalBounds() returns the
// restored (un-maximized) rect, so re-maximizing next launch still restores to
// a sane size. Debounced because resize/move fire in bursts while dragging.
// restored (un-maximized, un-fullscreen) rect, so re-maximizing / re-entering
// full screen next launch still restores to a sane size. Debounced because
// resize/move fire in bursts while dragging.
let persistTimer: ReturnType<typeof setTimeout> | null = null
const persistBounds = (): void => {
if (win.isDestroyed()) return
windowStateStore.save({ bounds: win.getNormalBounds(), isMaximized: win.isMaximized() })
windowStateStore.save({
bounds: win.getNormalBounds(),
isMaximized: win.isMaximized(),
isFullScreen: win.isFullScreen()
})
}
const schedulePersist = (): void => {
if (persistTimer) clearTimeout(persistTimer)
Expand All @@ -70,6 +78,8 @@ function createWindow(): void {
win.on('move', schedulePersist)
win.on('maximize', schedulePersist)
win.on('unmaximize', schedulePersist)
win.on('enter-full-screen', schedulePersist)
win.on('leave-full-screen', schedulePersist)
win.on('close', () => {
if (persistTimer) clearTimeout(persistTimer)
persistBounds() // flush synchronously before the window goes away
Expand Down
18 changes: 13 additions & 5 deletions src/main/store/windowStateStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import type { WindowBounds } from './windowStateCore'

interface WindowStateFile {
version: 1
/** Last *normal* (un-maximized) bounds; null until the user resizes once. */
/** Last *normal* (un-maximized, un-fullscreen) bounds; null until first resize. */
bounds: WindowBounds | null
/** Re-maximize on next launch if the window was maximized at close. */
isMaximized: boolean
/** Re-enter native full screen on next launch if it was full screen at close. */
isFullScreen: boolean
}

/**
Expand All @@ -19,7 +21,7 @@ interface WindowStateFile {
*/
class WindowStateStore {
private filePath = ''
private data: WindowStateFile = { version: 1, bounds: null, isMaximized: false }
private data: WindowStateFile = { version: 1, bounds: null, isMaximized: false, isFullScreen: false }

init(): void {
this.filePath = join(app.getPath('userData'), 'window-state.json')
Expand All @@ -29,7 +31,8 @@ class WindowStateStore {
this.data = {
version: 1,
bounds: parsed.bounds ?? null,
isMaximized: parsed.isMaximized ?? false
isMaximized: parsed.isMaximized ?? false,
isFullScreen: parsed.isFullScreen ?? false
}
} catch {
// Corrupt file → fall back to defaults (window state is non-critical).
Expand All @@ -41,8 +44,13 @@ class WindowStateStore {
return this.data
}

save(state: { bounds: WindowBounds; isMaximized: boolean }): void {
this.data = { version: 1, bounds: state.bounds, isMaximized: state.isMaximized }
save(state: { bounds: WindowBounds; isMaximized: boolean; isFullScreen: boolean }): void {
this.data = {
version: 1,
bounds: state.bounds,
isMaximized: state.isMaximized,
isFullScreen: state.isFullScreen
}
try {
writeFileSync(this.filePath, JSON.stringify(this.data, null, 2), 'utf8')
} catch {
Expand Down