| 1 | export interface WindowRect { |
| 2 | x: number; |
| 3 | y: number; |
| 4 | width: number; |
| 5 | height: number; |
| 6 | } |
| 7 | |
| 8 | export interface PersistedBoundsSource { |
| 9 | getNormalBounds(): WindowRect; |
| 10 | } |
| 11 | |
| 12 | // Query normal-state bounds rather than the maximized outer frame. MainWindow |
| 13 | // retains the last non-minimized snapshot while iconic because some native |
| 14 | // implementations return the maximized frame from getNormalBounds then. |
| 15 | export function persistedWindowRect(win: PersistedBoundsSource): WindowRect { |
| 16 | return win.getNormalBounds(); |
| 17 | } |
| 18 | |
| 19 | // All rectangles are Electron DIP coordinates. Display origins may be negative. |
| 20 | // The caller selects the matching display; this function only fits the rectangle. |
| 21 | export function restoreWindowRect( |
| 22 | size: { width: number; height: number; minWidth: number; minHeight: number }, |
| 23 | position: { x: number; y: number } | undefined, |
| 24 | workArea: WindowRect, |
| 25 | ): WindowRect { |
| 26 | const width = Math.min(Math.max(Math.round(size.width), size.minWidth), workArea.width); |
| 27 | const height = Math.min(Math.max(Math.round(size.height), size.minHeight), workArea.height); |
| 28 | const intersects = position && position.x < workArea.x + workArea.width && |
| 29 | position.y < workArea.y + workArea.height && |
| 30 | position.x + size.width > workArea.x && position.y + size.height > workArea.y; |
| 31 | const x = intersects ? position.x : workArea.x + Math.floor((workArea.width - width) / 2); |
| 32 | const y = intersects ? position.y : workArea.y + Math.floor((workArea.height - height) / 2); |
| 33 | return { |
| 34 | x: Math.round(Math.max(workArea.x, Math.min(x, workArea.x + workArea.width - width))), |
| 35 | y: Math.round(Math.max(workArea.y, Math.min(y, workArea.y + workArea.height - height))), |
| 36 | width, |
| 37 | height, |
| 38 | }; |
| 39 | } |
| 40 |