* 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>