Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* Pure geometry helpers for window-state.json — restoring the main window's
|
||||
* size, position, and maximized flag across launches. Side-effect-free so the
|
||||
* part that actually matters (rejecting garbage + off-screen bounds) is
|
||||
* unit-testable without booting Electron; main.ts owns the file I/O and the
|
||||
* live `screen` displays.
|
||||
*/
|
||||
|
||||
// Defaults mirror the historical hardcoded BrowserWindow size; MIN_* mirror its
|
||||
// minWidth/minHeight so a restored size never undershoots what the live window
|
||||
// allows. A fresh install (no saved state) is byte-identical to before.
|
||||
const DEFAULT_WIDTH = 1220
|
||||
const DEFAULT_HEIGHT = 800
|
||||
const MIN_WIDTH = 400
|
||||
const MIN_HEIGHT = 620
|
||||
|
||||
// Keep at least this much of the window over a display work area before we trust
|
||||
// a saved position, so the title bar stays grabbable after a monitor unplugs.
|
||||
const MIN_VISIBLE = 48
|
||||
|
||||
const finite = v => typeof v === 'number' && Number.isFinite(v)
|
||||
const clamp = (v, lo, hi) => Math.max(lo, Math.min(v, hi))
|
||||
|
||||
interface SanitizedWindowState {
|
||||
width: number
|
||||
height: number
|
||||
isMaximized: boolean
|
||||
x?: number
|
||||
y?: number
|
||||
}
|
||||
|
||||
// Parse raw JSON → clean state, or null if garbage. width/height are required
|
||||
// and floored; x/y survive only as a finite pair; isMaximized is strict.
|
||||
function sanitizeWindowState(raw?: any): SanitizedWindowState | null {
|
||||
if (!raw || typeof raw !== 'object' || !finite(raw.width) || !finite(raw.height)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const state: SanitizedWindowState = {
|
||||
width: Math.max(MIN_WIDTH, Math.round(raw.width)),
|
||||
height: Math.max(MIN_HEIGHT, Math.round(raw.height)),
|
||||
isMaximized: raw.isMaximized === true
|
||||
}
|
||||
|
||||
if (finite(raw.x) && finite(raw.y)) {
|
||||
state.x = Math.round(raw.x)
|
||||
state.y = Math.round(raw.y)
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
// True when `bounds` overlaps some display's work area by ≥ MIN_VISIBLE on both
|
||||
// axes. `displays` is Electron's screen.getAllDisplays() shape.
|
||||
function onScreen(bounds, displays) {
|
||||
if (!Array.isArray(displays)) {
|
||||
return false
|
||||
}
|
||||
|
||||
return displays.some(({ workArea: a } = {}) => {
|
||||
if (!a) {
|
||||
return false
|
||||
}
|
||||
|
||||
const x = Math.min(bounds.x + bounds.width, a.x + a.width) - Math.max(bounds.x, a.x)
|
||||
const y = Math.min(bounds.y + bounds.height, a.y + a.height) - Math.max(bounds.y, a.y)
|
||||
|
||||
return x >= MIN_VISIBLE && y >= MIN_VISIBLE
|
||||
})
|
||||
}
|
||||
|
||||
interface WindowOptions {
|
||||
width: number
|
||||
height: number
|
||||
x?: number
|
||||
y?: number
|
||||
}
|
||||
|
||||
// Sanitized state (or null) → BrowserWindow size/position options. Always sets
|
||||
// width/height, capped to the largest current display so a size saved on a
|
||||
// since-disconnected bigger monitor can't exceed any screen the user now has.
|
||||
// Sets x/y only when still on-screen; otherwise Electron centers the window.
|
||||
function computeWindowOptions(state, displays): WindowOptions {
|
||||
const opts: WindowOptions = {
|
||||
width: finite(state?.width) ? state.width : DEFAULT_WIDTH,
|
||||
height: finite(state?.height) ? state.height : DEFAULT_HEIGHT
|
||||
}
|
||||
|
||||
const cap = (Array.isArray(displays) ? displays : []).reduce(
|
||||
(m, { workArea: a } = {}) =>
|
||||
a && finite(a.width) && finite(a.height)
|
||||
? { width: Math.max(m.width, a.width), height: Math.max(m.height, a.height) }
|
||||
: m,
|
||||
{ width: 0, height: 0 }
|
||||
)
|
||||
|
||||
if (cap.width && cap.height) {
|
||||
opts.width = clamp(opts.width, MIN_WIDTH, cap.width)
|
||||
opts.height = clamp(opts.height, MIN_HEIGHT, cap.height)
|
||||
}
|
||||
|
||||
if (
|
||||
state &&
|
||||
finite(state.x) &&
|
||||
finite(state.y) &&
|
||||
onScreen({ x: state.x, y: state.y, width: opts.width, height: opts.height }, displays)
|
||||
) {
|
||||
opts.x = state.x
|
||||
opts.y = state.y
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
// Trailing debounce: collapse a burst of resize/move events (Linux fires many
|
||||
// mid-drag) into a single run `delayMs` after the last. `.flush()` runs now and
|
||||
// cancels the pending timer — used on close, before the window is gone.
|
||||
function debounce(fn, delayMs) {
|
||||
let timer = null
|
||||
|
||||
const debounced = () => {
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
timer = null
|
||||
fn()
|
||||
}, delayMs)
|
||||
}
|
||||
|
||||
debounced.flush = () => {
|
||||
clearTimeout(timer)
|
||||
timer = null
|
||||
fn()
|
||||
}
|
||||
|
||||
return debounced
|
||||
}
|
||||
|
||||
// The geometry events worth persisting from. `moved` and `resized` — the
|
||||
// settled-once-per-drag pair — are macOS/Windows only (Electron tags them
|
||||
// `@platform darwin,win32`), so a window bound to those alone never saves its
|
||||
// place on Linux: the events simply never arrive. `move` and `resize` carry no
|
||||
// platform tag and fire everywhere. They also fire continuously mid-drag, which
|
||||
// is what the trailing debounce above is for — and once a burst collapses to a
|
||||
// single trailing run, the settled events add nothing the debounce hasn't
|
||||
// already given us.
|
||||
const GEOMETRY_EVENTS = ['move', 'resize']
|
||||
|
||||
// Bind `schedule` to every geometry event, on a BrowserWindow or any emitter
|
||||
// with `.on`. One call site per window so the platform reasoning above can't be
|
||||
// half-applied to one window and not the other.
|
||||
function bindGeometryPersistence(win, schedule) {
|
||||
for (const event of GEOMETRY_EVENTS) {
|
||||
win.on(event, schedule)
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
bindGeometryPersistence,
|
||||
computeWindowOptions,
|
||||
debounce,
|
||||
DEFAULT_HEIGHT,
|
||||
DEFAULT_WIDTH,
|
||||
GEOMETRY_EVENTS,
|
||||
MIN_HEIGHT,
|
||||
MIN_VISIBLE,
|
||||
MIN_WIDTH,
|
||||
onScreen,
|
||||
sanitizeWindowState
|
||||
}
|
||||
Reference in New Issue
Block a user