Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 43 additions & 3 deletions apps/code/src/main/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,26 @@ import { container } from "./di/container";
import { AUTH_SERVICE, UPDATES_SERVICE } from "./di/tokens";
import { isDevBuild } from "./utils/env";
import { getLogFilePath } from "./utils/logger";
import { saveZoomLevel } from "./utils/store";

// Zoom is measured in Electron "levels" (factor = 1.2 ** level; 0 = 100%).
// ZOOM_STEP is one Zoom In/Out notch; the bounds clamp the level so a runaway
// accelerator can't persist an unusable zoom across restarts.
const ZOOM_STEP = 0.5;
const ZOOM_MIN = -3;
const ZOOM_MAX = 3;

// Apply a zoom change to the focused window and persist the new level so it
// survives restarts. `delta` adjusts relative to the current level; "reset"
// returns to 100%.
function applyZoom(delta: number | "reset"): void {
Comment thread
pauldambra marked this conversation as resolved.
const webContents = BrowserWindow.getFocusedWindow()?.webContents;
if (!webContents) return;
const next = delta === "reset" ? 0 : webContents.getZoomLevel() + delta;
const level = Math.max(ZOOM_MIN, Math.min(ZOOM_MAX, next));
webContents.setZoomLevel(level);
saveZoomLevel(level);
}

function findLatestCrashDump(): string | null {
const pendingDir = path.join(app.getPath("crashDumps"), "pending");
Expand Down Expand Up @@ -308,9 +328,29 @@ function buildViewMenu(): MenuItemConstructorOptions {
},
{ role: "toggleDevTools" },
{ type: "separator" },
{ role: "resetZoom" },
{ role: "zoomIn" },
{ role: "zoomOut" },
{
label: "Actual Size",
accelerator: "CmdOrCtrl+0",
click: () => applyZoom("reset"),
},
{
label: "Zoom In",
accelerator: "CmdOrCtrl+Plus",
click: () => applyZoom(ZOOM_STEP),
},
// Hidden duplicate so Cmd+= (i.e. Cmd++ without Shift) also zooms in,
// matching the built-in zoomIn role's dual accelerator.
{
label: "Zoom In",
accelerator: "CmdOrCtrl+=",
visible: false,
click: () => applyZoom(ZOOM_STEP),
},
{
label: "Zoom Out",
accelerator: "CmdOrCtrl+-",
click: () => applyZoom(-ZOOM_STEP),
},
{ type: "separator" },
{ role: "togglefullscreen" },
{ type: "separator" },
Expand Down
6 changes: 6 additions & 0 deletions apps/code/src/main/utils/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface WindowStateSchema {
width: number;
height: number;
isMaximized: boolean;
zoomLevel: number;
}

const userDataDir = getUserDataDir();
Expand All @@ -50,5 +51,10 @@ export const windowStateStore = new Store<WindowStateSchema>({
width: 1200,
height: 600,
isMaximized: true,
zoomLevel: 0,
},
});

export function saveZoomLevel(level: number): void {
windowStateStore.set("zoomLevel", level);
}
23 changes: 22 additions & 1 deletion apps/code/src/main/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ import { trpcRouter } from "./trpc/router";
import { collectMemorySnapshot } from "./utils/crash-diagnostics";
import { isDevBuild } from "./utils/env";
import { logger, readChromiumLogTail } from "./utils/logger";
import { type WindowStateSchema, windowStateStore } from "./utils/store";
import {
saveZoomLevel,
type WindowStateSchema,
windowStateStore,
} from "./utils/store";

const log = logger.scope("window");

Expand All @@ -44,6 +48,7 @@ function getSavedWindowState(): WindowStateSchema {
width: windowStateStore.get("width", 1200),
height: windowStateStore.get("height", 600),
isMaximized: windowStateStore.get("isMaximized", true),
zoomLevel: windowStateStore.get("zoomLevel", 0),
};

// Validate position is still on a connected display
Expand Down Expand Up @@ -233,6 +238,22 @@ export function createWindow(): void {
mainWindow.once("ready-to-show", showWindow);
const showFallback = setTimeout(showWindow, 3000);

// Restore the zoom level once the renderer has loaded. Read the latest
// persisted value from the store (not the create-time snapshot) so zooming
// done during the session survives in-app reloads, which otherwise reset
// Chromium's per-webContents zoom.
mainWindow.webContents.on("did-finish-load", () => {
mainWindow?.webContents.setZoomLevel(windowStateStore.get("zoomLevel", 0));
});
Comment thread
pauldambra marked this conversation as resolved.

// Persist mouse-wheel/pinch zoom. Menu-driven zoom is persisted by the
// menu items themselves (see buildViewMenu in menu.ts).
mainWindow.webContents.on("zoom-changed", () => {
if (mainWindow) {
saveZoomLevel(mainWindow.webContents.getZoomLevel());
}
});

// Persist window state on changes
mainWindow.on(
"resize",
Expand Down
Loading