Repository navigation
perf(desktop): dispose the main window when it closes to the tray - #420
Conversation
A hidden main window kept its Skia/Metal resources and its whole UI tree for as long as Ketch stayed in the tray, which is where a download manager spends most of its time. The window now exists only while it shows, as the Settings window already did. What its content saves with rememberSaveable (the page, the filter, the search, scroll positions) is kept in a SaveableStateHolder outside the window and comes back when it reopens. On Apple Silicon (1280 x 800 window, empty list, idle), a window closed to the tray now leaves 365-440 MB instead of 405-460 MB: GPU memory falls to about 25 MB instead of 60 MB, and the rest of the window's graphics memory to about 1 MB instead of 18 MB. Four close and reopen cycles showed no growth. The testing guide records how to measure this, and what was tried and left out: capping Skia's GPU cache, double buffering, software rendering, Java2D on OpenGL and the serial collector.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8104e24756
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ) { | ||
| val app = @Composable { | ||
| App(controller, activityEvents = activityEvents, fileLogger = launch.fileLogger) | ||
| windowStates.SaveableStateProvider(MAIN_WINDOW_STATE) { |
There was a problem hiding this comment.
Save the list scroll state before disposing the window
When a user closes Ketch to the tray after scrolling the Downloads list, this provider does not preserve that position: DownloadsScreen creates DownloadsPage with remember, and DownloadsPage owns a plain LazyListState, so neither participates in this SaveableStateHolder. Removing the Window therefore destroys the list state and reopening starts at the top; make the list position saveable or hoist it outside the disposable window.
AGENTS.md reference: AGENTS.md:L512-L515
Useful? React with 👍 / 👎.
Test Results 1 392 files ±0 1 419 suites ±0 9m 56s ⏱️ -8s Results for commit 8104e24. ± Comparison against base commit e50759c. This pull request removes 1 and adds 1 tests. Note that renamed tests count towards both. |
What
Closing the main window to the tray (menu bar on macOS) now disposes it instead of hiding it, as the Settings window already did. What its content saves with
rememberSaveable(the page, the filter, the search, scroll positions) is kept in aSaveableStateHolderoutside the window, so it reopens where it was left. Only transient overlays, such as an open command palette, reset.Why
A hidden window kept its Skia/Metal device and its whole UI tree for as long as Ketch stayed in the tray, which is where a download manager spends most of its time.
Measurements
Apple Silicon, 1280 × 800 window, empty list, 60 s idle, physical footprint (what Activity Monitor shows):
Also documented
docs/development/testing.mdnow records how to measure (footprint, not RSS), where the memory goes, and what was tried and left out:Testing
./gradlew :app:desktop:test: 258 tests pass.LWWindowPeer.lastCommonMouseEventPeeruntil another window gets a mouse event, with no native resources attached.