feat: add "start in fullscreen" window preference

Adds an opt-in preference that launches the main window in fullscreen,
driven by feedBack core's Settings → System "Fullscreen" toggle. Wires
the window.feedBackDesktop.window bridge (getStartFullscreen /
setStartFullscreen) that core's setupWindowOptions() gates on, persists
the flag in the desktop config (DesktopConfig.startFullscreen, alongside
windowBounds), and passes `fullscreen: true` at BrowserWindow creation
when set.

Persistence lives here (not renderer localStorage) because the main
process must read the pref at window-creation time. setStartFullscreen
live-applies via setFullScreen so the toggle is responsive on
Windows/Linux; on macOS the first programmatic fullscreen-enter on a
window created windowed is dropped by AppKit, so there it takes effect on
next launch — the core Settings copy notes this. This intentionally
narrows the earlier "never launch fullscreen" default to an opt-in.

Signed-off-by: gionnibgud <gionnibgud@gmail.com>
This commit is contained in:
gionnibgud
2026-07-13 13:44:33 +02:00
parent 6884800fd8
commit 4f1b64ff73
4 changed files with 49 additions and 3 deletions
+26 -3
View File
@@ -117,6 +117,8 @@ import {
IPC_UPDATE_CHECK_NOW,
IPC_UPDATE_APPLY,
IPC_POWER_SET_SCREEN_AWAKE,
IPC_WINDOW_GET_START_FULLSCREEN,
IPC_WINDOW_SET_START_FULLSCREEN,
} from './ipc-channels';
import { initAudioBridge, shutdownAudio } from './audio-bridge';
import { initDebugLogging, isDebugEnabled } from './debug-log';
@@ -469,6 +471,7 @@ function createWindow(port: number): void {
getDesktopConfig().windowBounds,
screen.getAllDisplays().map((d) => d.workArea),
);
const startFullscreen = getDesktopConfig().startFullscreen === true;
mainWindow = new BrowserWindow({
x: restored.x,
y: restored.y,
@@ -476,6 +479,7 @@ function createWindow(port: number): void {
height: restored.height,
minWidth: MIN_WIDTH,
minHeight: MIN_HEIGHT,
fullscreen: startFullscreen,
title: 'fee[dB]ack',
backgroundColor: '#0f172a', // slate-900 to match Slopsmith UI
webPreferences: rendererWebPreferences,
@@ -484,9 +488,11 @@ function createWindow(port: number): void {
// Persist geometry on close. getNormalBounds() so a maximized session
// saves the underlying windowed size, restored + re-maximized next launch.
// ponytail: fullscreen is deliberately not persisted (launching straight
// into fullscreen is jarring, especially on macOS) and we save on close
// only — a crash loses the last session's geometry; add debounced
// Fullscreen is NOT auto-persisted from the live window state (launching
// straight into fullscreen is jarring, especially on macOS); it launches
// fullscreen ONLY when the user opts in via Settings → System → "Start in
// fullscreen" (config.startFullscreen, applied above). We save geometry on
// close only — a crash loses the last session's geometry; add debounced
// resize/move saving if that ever matters.
mainWindow.on('close', () => {
if (!mainWindow || mainWindow.isDestroyed()) return;
@@ -1272,6 +1278,23 @@ async function startup(): Promise<void> {
return { success: true, enabled: on, urls: getLanUrls() };
});
ipcMain.handle(IPC_WINDOW_GET_START_FULLSCREEN, () => getDesktopConfig().startFullscreen === true);
ipcMain.handle(IPC_WINDOW_SET_START_FULLSCREEN, (_event, on: unknown) => {
const value = on === true;
setDesktopConfig({ startFullscreen: value });
// Live-apply so the toggle is responsive, not silent-until-relaunch.
// Works on the first toggle on Windows/Linux. On macOS the FIRST enter on
// a window created windowed is dropped by AppKit (its native-fullscreen
// state machine isn't engaged until the window has been fullscreen once —
// creating with `fullscreen: true` engages it), so there it takes effect
// on next launch instead; the core Settings note tells macOS users that.
// Reliable live both ways once the window has entered fullscreen once.
if (mainWindow && !mainWindow.isDestroyed() && mainWindow.isFullScreen() !== value) {
mainWindow.setFullScreen(value);
}
return value;
});
// Auto-update (Velopack). The renderer Settings panel reads the persisted
// channel from localStorage and calls setChannel() on boot — we default
// to 'stable' here so the first check runs against the safest feed even