Skip to content

fix(desktop): persist zoom across app restarts - #50169

Closed
mitivil wants to merge 1 commit into
anomalyco:devfrom
mitivil:persist-window-zoom
Closed

mitivil wants to merge 1 commit into
anomalyco:devfrom
mitivil:persist-window-zoom

Conversation

@mitivil

@mitivil mitivil commented Sep 20, 2026

Copy link
Copy Markdown

Issue for this PR

Closes #50168
Closes #49096

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Desktop zoom selected with Ctrl++ / Ctrl+- returns to 100% after quitting and reopening OpenCode. Persist the last selected factor in the existing main-process appearance settings and restore it for both early and regular windows.

Keyboard/renderer, native menu and pinch changes use the same setter. Disabling pinch zoom preserves the selected scale. Missing or invalid stored values fall back to 100%; reset-to-100% is saved too.

How did you verify your code works?

  • bun run check passed (lint and 35 typecheck tasks).
  • 17 focused desktop tests passed, including a real Electron regression test using two separate processes and an isolated temporary profile. It checks relaunch, reload, pinch toggling, reset, limits and invalid settings.
  • Confirmed the regression test fails when the persistence write is removed.

Screenshots / recordings

No layout or copy changes. The Electron test verifies the before/after behavior: a selected 140% scale is restored after relaunch instead of returning to 100%.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions

Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

@DonMecca DonMecca left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirming this against a real reproduction on 2.0.18.

I independently reproduced both linked issues on OpenCode Desktop 2.0.18 (macOS 27.0, arm64, Electron 44.4.3 / Chrome 152) and traced the cause to the unconditional win.webContents.setZoomFactor(1) at the top of wireZoom (packages/desktop/src/main/windows.ts), versus the guarded equivalent later in the same function.

Two details from my investigation that this PR appears to handle, in case they're useful for review:

  1. Chromium already persists the value. Preferences → partition.per_host_zoom_levels holds a real per-origin zoom factor that tracks user gestures. The app restores it and then discards it. So the fix is genuinely a persistence-and-restore problem, not a "nothing is saved" one — consistent with storing zoomFactor in opencode.settings.

  2. The early window matters. The reset applies to the early/pre-window path too, which is why the shell visibly renders at the restored zoom for a moment at launch before shrinking. Restoring for both early and regular windows (as this PR does) is the right shape.

I also verified the current bundle contains no ZOOM_FACTOR_KEY, so nothing user-side can work around this today — the change needs to ship.

CI is green and the branch reports mergeable. Thanks for writing this up with a two-process Electron relaunch test; happy to re-verify on macOS once there's a build to test.

@darknose

Copy link
Copy Markdown

Bumping with an independent verification that this is still needed and that the approach looks right.

  • Reproduced on the current latest build, Desktop 2.0.31, macOS 27.0 arm64: Cmd + a few steps, full quit, reopen → 100%.
  • Bundle inspection of 2.0.31 matches the analysis in Desktop zoom resets to 100% after restarting the app #50168: the unconditional setZoomFactor(1) in wireZoom is the cause; the renderer keeps zoom in memory only and no key is persisted, so nothing user-side can work around it.
  • Restoring for both the early and regular window paths (as this PR does) is the right shape — the shell is briefly visible at the restored zoom before the current reset clobbers it.
  • CI is green and the branch reports mergeable.
  • Confirm this closes Desktop v1.18.31 , Pinch to zoom disable resets UI zoom #49096 as well (the pinch-zoom-disabled reset shares the same root cause).

Bumping for code-owner review (@Hona, @Brendonovich): this is a daily papercut for anyone on macOS who needs a larger UI, and it is a clear v2 regression from the 1.x behaviour.

Small request: can review confirm the persisted key lives in the appearance settings store? #54499 / #44184 add appearance.fontSize (and line-height) to the same appearance settings. Keeping zoom in that same store, or clearly adjacent to it, would avoid two competing scale systems later. Happy to re-test on macOS once there is a build.

@darknose

Copy link
Copy Markdown

Heads-up on the current state: as of now this PR reports mergeable: CONFLICTING / mergeStateStatus: DIRTY against dev, so it can't be merged as-is — it needs a rebase onto current dev first.

Everything else still looks good: not a draft, the bot checks (standards / compliance / duplicates) all pass, and this remains the only open PR that fixes the zoom-persistence bug (#50168). #54499 is the font-size/line-height work, not a substitute for this.

Ping for a rebase and a code-owner review (@Hona, @Brendonovich) when you have a moment — this is a small, self-contained fix (7 files) that resolves a long-standing v2 regression.

@wc4440222

Copy link
Copy Markdown

Adding a second data point in case it helps with prioritization.

  • Platform: Windows 11, Desktop 2.0.32 (freshly installed today, 2026-10-17)
  • Reproduces exactly as described: Ctrl +/- changes zoom for the current run only; after a full quit and relaunch it is back to 100%
  • Current workaround is --force-device-scale-factor=1.25 in the shortcut, which is a global scale hack rather than a fix — per-window zoom is what is actually wanted, and it is the single most annoying thing in the desktop app for us right now

This has been open since 2026-09-20 and is still not in any release up to 2.0.32. Happy to install a build with this patch applied and report back if a prebuilt artifact or CI build is available.

@darknose

Copy link
Copy Markdown

Consolidating the reports in one place, since this is now confirmed across platforms and versions.

Still present on the current release: OpenCode Desktop 2.0.32, freshly installed today (2026-10-17) — Ctrl +/- changes zoom for the current run only; after a full quit and relaunch it is back to 100%.

Confirmed across: macOS 27.0 arm64 (2.0.18, 2.0.19, 2.0.31, 2.0.32), Linux (2.0.11, 2.0.27), Windows 11 (2.0.27, 2.0.32). This is a clear v2 regression — 1.x restored the last selected zoom.

Root cause (unchanged): on window creation the main process runs wireZoom (packages/desktop/src/main/windows.ts), which calls win.webContents.setZoomFactor(1) unconditionally — the guarded call later in the same function shows the asymmetry. The renderer keeps zoom in memory only, there is no persisted key (opencode.settings has no zoom field, no ZOOM_FACTOR_KEY in the bundle), so Chromium's Preferences → partition.per_host_zoom_levels value is restored and then discarded.

On the --force-device-scale-factor workaround: it applies Chromium-level scaling before the app's reset, so it survives restarts, but it is a global scale hack, not the per-window zoom that is actually wanted.

Status of this PR: it is currently mergeable: CONFLICTING / mergeStateStatus: DIRTY against dev, so it needs a rebase before it can land; it also still needs a code-owner review. Everything else is green (bot checks pass, small self-contained change, 7 files).

I'll try to put together a rebased branch on top of current dev and drop a link here, so the change is ready to merge (or easy to pick up) without re-doing the conflict work — and @wc4440222 can test it as soon as there is a build.

@darknose

Copy link
Copy Markdown

Rebased this change onto current dev so it's mergeable again. Branch (in my fork):

Same fix, replayed on today's dev (7 files, +128/−25):

  • stores the last factor in the appearance settings (ZOOM_FACTOR_KEY = "zoomFactor"), clamped to 0.2–10, falling back to 1 on missing/invalid values
  • wireZoom restores storedZoomFactor() instead of setZoomFactor(1); the early window and windowAppearance apply it before first paint (including the win32 titlebar overlay)
  • setZoomFactor persists on change; disabling pinch zoom no longer resets the scale
  • the WindowSetZoomFactor IPC handler now routes through the persisting setZoomFactor (the native View menu already used it, so all paths persist)

Rebase notes:

  • conflicts were only in storage/keys.ts, windows/appearance.ts and ipc-handlers/window.ts; resolved keeping current dev formatting, so the diff has no unrelated churn
  • the tests moved from the old packages/desktop/test/ to co-located packages/desktop/src/main/windows/ (that's where dev puts desktop tests now) and their imports were updated

Caveat: I rebased on a machine without bun, so I did not run bun run check or the Electron test locally — CI should. @mitivil, feel free to pull this branch into your PR (or cherry-pick the commit) if that's easier than rebasing yourself.

@wc4440222

Copy link
Copy Markdown

Thanks for consolidating all of this — I'm the Windows 11 / 2.0.32 data point in that table, so I can confirm those numbers are current.

One thing worth flagging while the reports are fresh, because it's the actual blocker right now: as of 2026-10-18 this PR still reports mergeable: false / mergeStateStatus: DIRTY against dev. I re-checked just now. Your rebase lives in darknose:fix/zoom-persist-rebased, but nothing has been pushed to mitivil:persist-window-zoom and no new PR has been opened from it — so the work is done but not yet in a state anyone can review or merge.

Two concrete asks:

  1. @mitivil — either fast-forward persist-window-zoom to 46f7afcfd (force-push is fine here, the rebase preserves your commit message and authorship), or open a fresh PR from the rebased branch and link it back to this one. Whichever is less work for you. Otherwise this stays stuck even though the fix is ready.
  2. After that, the remaining blocker is a code-owner review — everything else is green (bot checks pass, non-draft, small and self-contained).

On testing: I'm happy to be the Windows verification for this. I can't build the desktop app from source on this machine, but if CI publishes an artifact for the branch — or anyone produces a build — I'll install it and report before/after with the exact version string.

For context on why this matters to us: the current workaround (--force-device-scale-factor=1.25 in the shortcut) is Chromium-level global scaling, not per-window zoom. It survives restarts, but it changes everything at once, so it isn't equivalent to what the fix does.

@darknose

Copy link
Copy Markdown

Opened #56802 from the rebased branch so there is a mergeable target to review: it applies cleanly to dev (MERGEABLE, bot checks pass) and carries the same change with authorship and the original commit message preserved.

So this PR is now effectively superseded by #56802. Options:

Either is fine — the point is just to get the fix into a state a code owner can merge.

@opencode-agent

Copy link
Copy Markdown
Contributor

Thanks for working on this, and for the cross-platform testing in the thread. Zoom persistence landed in #59277: Settings → Appearance now has a Zoom select (100–200%), and the chosen level is saved and restored on launch. Keyboard and menu zoom step through the same levels. We went with fixed levels instead of saving any zoom factor, so pinch zoom stays temporary. Closing this in favour of that change.

@opencode-agent opencode-agent Bot closed this Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Desktop zoom resets to 100% after restarting the app Desktop v1.18.31 , Pinch to zoom disable resets UI zoom

4 participants