Commit Graph
3 Commits
Author SHA1 Message Date
topkoa 030559dd38 fix(panes): only the main window may drive the tray; clamp fallback defaults
1. pane:sync was accepted from ANY renderer with the preload bridge. Pane
   windows are same-origin top-level frames, so preload's isMainFrame gate hands
   them the bridge too — which means a pane window (or any allowed pop-up) could
   send pane:sync and overwrite the tray's registry, most simply by pushing an
   empty list and emptying the menu.

   Exactly one renderer owns the pane registry. It is now accepted from that one
   only: event.sender must be the main window's webContents.

2. sanitizeWindowBounds returned sizing.defaultWidth/Height unclamped. The min
   clamp only runs when `saved` parses, so a caller whose defaults undercut its
   own minimums would get a window below the floor on precisely the paths where
   nothing is saved — first launch, or a corrupt config — and a correctly sized
   one everywhere else.

   That is the worst shape a bug can have: invisible in the common case, and
   visible only to a new user. The fallback is clamped to the floor now, with a
   test.

window-bounds: 14/14.
Signed-off-by: topkoa <topkoa@gmail.com>
2026-07-12 21:18:05 -04:00
topkoa 313d1e5d5b fix(panes): persist alwaysOnTop, flush geometry on quit, test the sizing override
Five more from review.

1. alwaysOnTop was RESTORED but never SAVED. A dead read: the only way to turn
   it on was to hand-edit the config file. There is now one snapshot() that
   decides what "remembered" means, used by the debounced save, the flush on
   close, and the flush on quit — so the three can never disagree about it again.

2. GEOMETRY WAS LOST ON QUIT. closeAllPanes() calls destroy(), and destroy()
   does not fire 'close' — so the flush wired to that event never ran on the one
   path every user takes. Combined with the 400ms debounce: move a pane, quit two
   seconds later, and its position was gone. Every pane is flushed before its
   window is destroyed.

3. The tray-icon comment claimed a 16px PNG; build:ts copies the 32px one. Also
   spelled out what the macOS consequence actually is (a colour icon rather than
   one that adapts to light/dark menu bars), rather than gesturing at it.

4. sanitizeWindowBounds' new `sizing` parameter had no tests — and it is the
   whole reason the function was touched. Without it a 380x560 pane restored
   through the MAIN window's 800x600 floor is silently inflated to three times
   the size the plugin asked for. Four tests now pin it: a small pane is not
   inflated, the min clamp uses the override, corrupt input falls back to the
   override's defaults, and — the one that protects everyone else — omitting
   `sizing` leaves the main window's behaviour byte-for-byte unchanged.

window-bounds tests: 13/13.

Signed-off-by: topkoa <topkoa@gmail.com>
2026-07-12 21:12:04 -04:00
6349ed4c5f feat(window): persist main window size/position across launches (#97)
Addon CI / addon (arm64, macos-14, mac) (push) Waiting to run
Addon CI / addon (x64, ubuntu-22.04, linux) (push) Waiting to run
Addon CI / addon (x64, windows-latest, win) (push) Waiting to run
Ship CI / CI (push) Waiting to run
* feat(window): persist main window size/position across launches

The main window always opened at a fixed 1400x900, forcing a manual
resize every session. Save the window geometry (normal bounds +
maximized flag) to the existing desktop prefs store on close, and
restore it in createWindow.

Saved bounds are validated by a pure sanitizer against the current
display layout before use, so stale state degrades safely instead of
producing an off-screen or absurd window:
- garbage/partial config -> 1400x900 centered defaults
- size clamped between the 800x600 window minimums and the largest
  display's workArea
- position kept only when the window overlaps a display by at least
  100x50 px (unplugged monitor / resolution change -> re-center);
  negative multi-monitor coordinates remain valid
- maximized sessions save getNormalBounds() and re-maximize on
  restore; fullscreen deliberately restores windowed

No new dependency; reuses get/setDesktopConfig (atomic write,
fail-soft) in soundfont-manager.ts. The store file is already in the
reset-app-settings delete-set, so a config reset also resets bounds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: gionnibgud <gionnibgud@gmail.com>

* fix(window): don't crash shutdown if bounds persistence write fails

The close listener called setDesktopConfig synchronously with no error
handling; a disk-full or permissions failure during the write would throw
unhandled inside the close handler, risking a shutdown crash. Wrap the
write in try/catch and log a warning instead. Flagged by CodeRabbit on PR #97.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: gionnibgud <gionnibgud@gmail.com>

---------

Signed-off-by: gionnibgud <gionnibgud@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 15:41:47 +02:00