Skip to content

feat: persist window size, position, and full screen state across launches#1083

Merged
datlechin merged 4 commits intomainfrom
worktree-window-state-persistence
May 7, 2026
Merged

feat: persist window size, position, and full screen state across launches#1083
datlechin merged 4 commits intomainfrom
worktree-window-state-persistence

Conversation

@datlechin
Copy link
Copy Markdown
Member

Summary

  • Restore last window size, position, and full screen state on launch instead of opening at 1200x800 every time.
  • First launch picks an initial editor size based on the connected display (about 85% of visibleFrame) instead of a fixed default.
  • Cover Editor, JSON Viewer, Integrations Activity, and Feedback windows.

Why

The editor always opened at the same default size, even after the user resized or full screened it. Three bugs combined to defeat persistence: a viewWillAppear upsize floor that silently discarded any restored frame smaller than 1200x800, a WindowManager.openTab window.center() call that wiped autosave-restored origins, and no full screen tracking at all (isRestorable = false opts out of Cocoa Resume).

How

Native macOS APIs only. No Cocoa Resume / NSWindowRestoration, which would race with AppLaunchCoordinator's custom session restore.

  • WindowFramePolicy (new): per-window-class value type (autosaveName, fullScreenStateKey, first-run sizing rules). Static instances for .editor, .jsonViewer, .integrationsActivity, .feedback.
  • WindowStateController (new): @MainActor singleton that calls setFrameAutosaveName + setFrameUsingName, computes first-run size, observes willEnterFullScreen / didExitFullScreen for full screen bool, and queues a one-shot didBecomeKey observer to call toggleFullScreen when the saved bool is true. Per-window observer lifetime managed by a private WindowStateBinding.
  • WindowChromeConfigurator gains an optional statePolicy so SwiftUI Window scenes (Integrations Activity) get persistence through the same NSViewRepresentable used for chrome config.
  • Removed the viewWillAppear upsize floor and the unconditional window.center(). Centering only happens on first run.
  • Deleted the 6-line NSWindow+FrameAutosave helper, replaced by the controller.

Off-screen handling uses Apple default behavior: setFrameUsingName clamps to the current main screen when the saved screen is gone.

Files

New:

  • TablePro/Core/Services/Infrastructure/WindowFramePolicy.swift
  • TablePro/Core/Services/Infrastructure/WindowStateController.swift
  • TableProTests/Services/WindowFramePolicyTests.swift

Modified:

  • TabWindowController.swift, WindowManager.swift, MainSplitViewController.swift, JSONViewerWindowController.swift, FeedbackWindowController.swift, WindowChromeConfigurator.swift, TableProApp.swift, CHANGELOG.md

Deleted:

  • TablePro/Extensions/NSWindow+FrameAutosave.swift

Test plan

  • Resize the editor, quit, relaunch. Window opens at the resized frame, not 1200x800.
  • Move the editor to a non-default position, quit, relaunch. Origin is restored.
  • Enter full screen, quit, relaunch. Window reopens in full screen.
  • Resize below 1200x800, quit, relaunch. The window stays at the smaller size (window.minSize of 720x480 still enforced).
  • First-launch on a fresh user defaults: window opens at ~85% of NSScreen.main.visibleFrame, centered.
  • Saved frame on a now-disconnected external display: relaunch on built-in display only. Frame clamps to current main screen.
  • Open multiple connection windows, resize one, quit, relaunch. All editor windows inherit the most recent saved frame (shared autosave name, matches Mail/Pages model).
  • JSON Viewer and Integrations Activity persist their frame independently.
  • Feedback panel still uses fitting size on first run.
  • xcodebuild test -only-testing:TableProTests/WindowFramePolicyFirstRunSizingTests passes.

datlechin added 4 commits May 7, 2026 19:35
Signed-off-by: Ngô Quốc Đạt <datlechin@gmail.com>
…roApp/TablePro into worktree-window-state-persistence

# Conflicts:
#	CHANGELOG.md
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.

1 participant