Skip to content

fix(desktop): preserve main window bounds#3851

Merged
juliusmarminge merged 13 commits into
pingdotgg:mainfrom
anirudhsama:t3code/preserve-macos-window-size
Jul 20, 2026
Merged

fix(desktop): preserve main window bounds#3851
juliusmarminge merged 13 commits into
pingdotgg:mainfrom
anirudhsama:t3code/preserve-macos-window-size

Conversation

@anirudhsama

@anirudhsama anirudhsama commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What Changed

Persist the desktop main window position and size across launches.

Move and resize updates are debounced. Maximized windows save their normal bounds, and fullscreen bounds are ignored. Saved bounds are restored only when the complete rectangle fits within a currently connected display; otherwise, the app uses the existing 1100 x 780 default size and lets Electron choose the position.

Why

The desktop app currently creates every main window with fixed dimensions and no persisted position, so restarting resets the user's window layout.

Fixes #1829.

Verification

  • 344 desktop tests passed
  • vp run typecheck
  • vp check
  • Regression coverage includes minimized Windows bounds and shutdown write flushing
  • Manually tested size and position restoration after a clean quit and relaunch on a physical macOS device

Checklist

  • This PR is small and focused
  • I explained what changed and why

Note

Preserve and restore main window bounds and sidebar width across sessions

  • The desktop app now saves the main window's position, size, and maximized state to settings on move/resize/maximize/unmaximize/close (with a 500ms debounce) and restores them on next launch if they fit within a connected display.
  • A new flushMainWindowBounds method on DesktopWindow is called during shutdown to ensure bounds are persisted before the app exits.
  • The web sidebar width is restored from local storage on load, clamped to valid min/max bounds, and the CSS variable is hydrated via useLayoutEffect to avoid a flash of the default width.
  • resolveInitialMainWindowBounds falls back to DEFAULT_MAIN_WINDOW_SIZE when persisted bounds don't fit any connected display, and logs a warning when display detection fails.

Macroscope summarized c28dfce.


Note

Low Risk
Localized desktop window/settings and web layout UX; no auth or data-path changes, with fallbacks when display lookup or bounds validation fails.

Overview
The desktop app persists main window position, size, and maximized state in DesktopAppSettings, restores them when opening the main window (only if the saved rectangle fits a connected display), and flushes pending bounds on window close and app shutdown via flushMainWindowBounds in DesktopLifecycle.

Bounds updates are debounced on move/resize/maximize; maximized, fullscreen, and minimized windows save normal bounds. Invalid or off-screen saved geometry falls back to defaults without overwriting disk until the user moves the window.

The web shell applies the stored thread sidebar width on first paint (threadSidebarWidth helpers + --sidebar-width on SidebarProvider, with useLayoutEffect hydration in the sidebar rail) to avoid a width flash on load.

Reviewed by Cursor Bugbot for commit c28dfce. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 10, 2026
@anirudhsama
anirudhsama marked this pull request as ready for review July 10, 2026 09:44
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7d187606-e1a0-42ec-8ebf-72b306d8f130

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread apps/desktop/src/window/DesktopWindow.ts
Comment thread apps/desktop/src/window/DesktopWindow.ts
@macroscopeapp

macroscopeapp Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces new window bounds persistence functionality with significant runtime behavior changes across settings, window lifecycle, and UI state management. Two unresolved review comments identify potential bugs (stale sidebar max width, race condition with maximized state). New features with substantive logic and unresolved findings warrant human review.

You can customize Macroscope's approvability policy. Learn more.

Comment thread apps/desktop/src/window/DesktopWindow.ts
juliusmarminge and others added 2 commits July 20, 2026 11:13
Resolve the DesktopWindow test conflict by preserving both window-bounds persistence coverage and the newer fullscreen event coverage.

Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/desktop/src/window/DesktopWindow.ts
Use BrowserWindow normal bounds during fullscreen persistence so an in-flight resize is not discarded on quit.

Co-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/desktop/src/window/DesktopWindow.ts
Comment thread apps/desktop/src/window/DesktopWindow.ts Outdated
- Save bounds on native maximize and unmaximize events
- Update coverage for maximized window persistence
Comment thread apps/desktop/src/window/DesktopWindow.ts Outdated
Co-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/web/src/components/threadSidebarWidth.ts Outdated
Comment thread apps/web/src/components/AppSidebarLayout.tsx
Comment thread apps/web/src/components/ui/sidebar.tsx
Co-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/desktop/src/window/DesktopWindow.ts Outdated
juliusmarminge and others added 2 commits July 20, 2026 14:34
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c28dfce. Configure here.

collapsible="offcanvas"
className="border-r border-border bg-card text-foreground"
resizable={{
maxWidth: sidebarMaximumWidth,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Stale sidebar max width

Medium Severity

The sidebar's maxWidth is calculated once using window.innerWidth but doesn't update when the window resizes. This causes the sidebar to remain capped at an outdated maximum width if the browser window grows, preventing it from being expanded further.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c28dfce. Configure here.

window.on("close", () => {
runFork(flushBoundsPersist);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maximized fallback races persistence gate

Medium Severity

fallbackWindowMaximized is taken from persisted settings while the deferred maximize() runs only later on reveal, after move/resize/maximize listeners are already registered. Until that restore finishes, live isMaximized() disagrees with the baseline, so scheduleBoundsPersist can treat startup restore events as a user change and overwrite unrestorable saved bounds.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c28dfce. Configure here.

@juliusmarminge
juliusmarminge merged commit 2c199aa into pingdotgg:main Jul 20, 2026
16 checks passed
@anirudhsama

Copy link
Copy Markdown
Contributor Author

Thank you!

adamfgr pushed a commit to agriffiths-bots/t3code that referenced this pull request Jul 21, 2026
* fix(server): resolve Claude SDK executable path on Windows npm installs (pingdotgg#3740)

* Fix project action preview settings persistence (pingdotgg#3842)

* fix(desktop): allow clipboard writes in the preview browser (pingdotgg#3889)

* fix(web): handle sidebar shortcut before editors (pingdotgg#3921)

* fix(server): recognize Bedrock-backed Claude as authenticated (pingdotgg#3931)

* Fix incorrect pluralization of “entry” (pingdotgg#3933)

* feat(server): title background-task work-log rows with the task name (pingdotgg#3751)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* fix: delegate OpenCode session titles to provider (pingdotgg#3720)

* Archive selected threads from the context menu (pingdotgg#3895)

* fix(cli): support force removing projects (pingdotgg#3922)

* fix: allow sidebar to be shrunk when wider than viewport (pingdotgg#2456)

Co-authored-by: Shoaib Ansari <shoaibansari@Shoaibs-Mac-mini.local>
Co-authored-by: Julius Marminge <julius0216@outlook.com>

* fix(codex): show web search query and url in tool call details (pingdotgg#2093)

Co-authored-by: Julius Marminge <julius0216@outlook.com>

* Add Codex launch arguments setting (pingdotgg#2892)

Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: Julius Marminge <jmarminge@gmail.com>
Co-authored-by: root <root@localhost.localdomain>

* [orchestration] Clear stale active turn when session becomes inactive (pingdotgg#3159)

Co-authored-by: Julius Marminge <julius0216@outlook.com>

* Regenerate Codex reset credit protocol bindings (pingdotgg#4173)

Co-authored-by: codex <codex@users.noreply.github.com>

* fix(preview): preserve direct localhost navigation (pingdotgg#3939)

Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>

* Synchronize mobile threads with authoritative shell snapshots (pingdotgg#4163)

Co-authored-by: codex <codex@users.noreply.github.com>

* Gate iOS glass layout on native support (pingdotgg#4032)

Co-authored-by: codex <codex@users.noreply.github.com>

* fix(opencode): resume the OpenCode session on follow-ups instead of starting an empty one (pingdotgg#3617)

Co-authored-by: codex <codex@users.noreply.github.com>

* fix(server): use CLI for OpenCode health check instead of spawning server (pingdotgg#4153)

* fix(web): scope timeline minimap hover target to the side gutter (pingdotgg#3869)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* [codex] show complete approval details (pingdotgg#4111)

* fix(web): paint text selection over composer chips (pingdotgg#4139)

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

* [codex] preserve custom model slugs (pingdotgg#4168)

* fix(web): preview workspace images in the file panel (pingdotgg#3996)

Co-authored-by: Rhiz3K <rhiz3k@protonmail.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>

* feat(web): drag files from the explorer into the chat composer (pingdotgg#4140)

Co-authored-by: Julius Marminge <julius0216@outlook.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

* fix(desktop): preserve main window bounds (pingdotgg#3851)

Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>

* perf(orchestration): speed up new-chat propagation and offline catch-up (pingdotgg#4177)

Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>

* Finale: upgrade changed files card to fix various UI issues (pingdotgg#4113)

Co-authored-by: Julius Marminge <julius0216@outlook.com>

* fix(web): always show environment chip for remote projects (pingdotgg#4217)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* chore: reconcile upstream sync (20260721) — typecheck/test fixups

Post-cherry-pick reconciliation of the shell/thread sync rewrite:
- adopt upstream's client shell.ts + shell-sync.test.ts (drops the fork's
  superseded #142 replay-gap watchdog; server no longer emits 'caught-up')
- remove the orphaned 'caught-up' contract member and obsolete fork shell
  server tests (upstream's coalescing tests cover the behavior)
- keep the fork's thread reconciliation, resubscribing via subscribeDynamic
  (establish base once; foreground/session resubscribe via the live cursor)
- add latestSequence to OrchestrationEngine test mocks; thread dispatch
  authority in bin.test; narrow stream-item unions past the new 'synchronized'

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Co-authored-by: David Whatley <nsxdavid@gmail.com>
Co-authored-by: coach007 <6238600+keeperxy@users.noreply.github.com>
Co-authored-by: Carlos Rico-Ospina <carlosricojr@gmail.com>
Co-authored-by: Andrew Barnes <bortstheboat@gmail.com>
Co-authored-by: Pieter van Zyl <20579513+PieterVanZyl-Dev@users.noreply.github.com>
Co-authored-by: mel <mcmelon@nodiumhosting.com>
Co-authored-by: Theo Browne <me@t3.gg>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Tristan Knight <tris203@gmail.com>
Co-authored-by: Christoph Herzog <a.github@omega-id.com>
Co-authored-by: Shoaib <shoaib050326@gmail.com>
Co-authored-by: Shoaib Ansari <shoaibansari@Shoaibs-Mac-mini.local>
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: Guilherme Vieira <46866023+GuilhermeVieiraDev@users.noreply.github.com>
Co-authored-by: James <105842516+jamesx0416@users.noreply.github.com>
Co-authored-by: Julius Marminge <jmarminge@gmail.com>
Co-authored-by: root <root@localhost.localdomain>
Co-authored-by: Andrew Forster <76947376+Andrew-Forster@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Chris Michael Guzman <67719167+Chrrxs@users.noreply.github.com>
Co-authored-by: Vadym Kotai <vdmkotai@gmail.com>
Co-authored-by: Utkarsh Patil <73941998+UtkarshUsername@users.noreply.github.com>
Co-authored-by: xxashxx-svg <xxanshxx9@gmail.com>
Co-authored-by: Maxwell Young <maxtheyoung@gmail.com>
Co-authored-by: Yordis Prieto <yordis.prieto@gmail.com>
Co-authored-by: Rhiz3K <33246262+Rhiz3K@users.noreply.github.com>
Co-authored-by: Rhiz3K <rhiz3k@protonmail.com>
Co-authored-by: Anirudh Coontoor <me@anirudhs.net>
Co-authored-by: Rusiru Sadathana <rusirusadathana@gmail.com>
Co-authored-by: ss <69873514+sandersonstabo@users.noreply.github.com>
Co-authored-by: wizzoapp[bot] <254688279+wizzoapp[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: window doesn't remember its place when reopened

2 participants