* refactor(desktop): extract titleBarOverlayOptions into a tested helper getTitleBarOverlayOptions in main.ts branched inline on mac/windows/wsl. Move the decision into titlebar-overlay-width.ts so the WSLg → false rule (renderer paints its own controls there) is unit-tested next to the width reservation it pairs with. main.ts keeps a thin caller. Co-authored-by: null-runner <nicholas.mariani@hotmail.it> * fix(desktop): renderer-drawn window controls on WSLg Under WSLg the frameless window (titleBarStyle: 'hidden') had no minimize/maximize/close. getTitleBarOverlayOptions returned false on the premise that the RDP host paints replacement controls; it does not for a frameless window. Electron's native overlay is not the fix either: its cluster's hit-region drifts from the rendered buttons under the RAIL compositor. The renderer now paints Windows-style min/max/close (wslg-window-controls) routed over a hermes:window-control IPC channel (window-controls.ts → preload → main). getWindowState reports customWindowControls/isMaximized so the renderer knows when to mount them and which glyph to show. The cluster is pinned to TITLEBAR_HEIGHT px (the contrib shell zeroes --titlebar-height for content subtrees) with 46px native-width caption buttons. Co-authored-by: Austin Pickett <pickett.austin@gmail.com> * fix(desktop): wire WSLg window-control IPC and snap maximize onto the work area Register hermes:window-control in main, report windowControlState from getWindowState, and re-send window state on maximize/unmaximize so the renderer's maximize/restore glyph tracks the window. maximizedBoundsCorrection snaps a WSLg-maximized frameless window back onto the display work area (RAIL can settle it offset — reported on WSLg 1.0.65). It is a no-op wherever native maximize already fills the work area, so healthy compositors are never fought and setBounds cannot loop. Co-authored-by: null-runner <nicholas.mariani@hotmail.it> * fix(desktop): call WSLg window-control bridge without the click event contextBridge structured-clones every argument, and a React SyntheticEvent is not cloneable, so onClick={controls.minimize} threw "An object could not be cloned" before ipcRenderer.send ran. The buttons rendered but did nothing. Wrap the handlers so the bridge is called with no arguments, and pin that in the test. * fix(desktop): remove recursive WSLg maximize bounds correction * fix(desktop): select native Wayland before Electron initialization on WSLg * fix(desktop): preserve ready pipe and debugger across WSLg launch * fix(desktop): keep WSLg caption controls scoped to every window * style(desktop): order window chrome event import --------- Co-authored-by: null-runner <nicholas.mariani@hotmail.it>
27 lines
873 B
TypeScript
27 lines
873 B
TypeScript
import { app } from 'electron'
|
|
|
|
import { wslgLaunchArgs } from './wslg-launch'
|
|
import { spawnWslgLaunch } from './wslg-launch-process'
|
|
|
|
const args = wslgLaunchArgs(process.argv.slice(1), process.env, process.platform)
|
|
|
|
if (args) {
|
|
// Keep the launcher alive until the child exits: npm's concurrently must not
|
|
// tear down Vite during this handoff. No backend, windows or single-instance
|
|
// lock are created in this parent. The child has an explicit platform flag,
|
|
// so it goes straight into main on its first pass.
|
|
const child = spawnWslgLaunch(args)
|
|
|
|
child.once('error', error => {
|
|
console.error('[hermes] WSLg launch failed:', error)
|
|
app.exit(1)
|
|
})
|
|
child.once('exit', code => app.exit(code ?? 1))
|
|
|
|
for (const signal of ['SIGINT', 'SIGTERM'] as const) {
|
|
process.once(signal, () => child.kill(signal))
|
|
}
|
|
} else {
|
|
await import('./main')
|
|
}
|