fix: prevent macOS desktop unlock freeze after display sleep#745
Merged
Conversation
Collaborator
|
hey @yuruiz apologies for the force push on main, i was going to rebase this but i see that you already merged. will look into your PRs in a moment. |
b97f281 to
590da87
Compare
7ec394c to
5c90449
Compare
macOS display sleep can leave Chromium's GPU-process display link stuck on a stale display, so the compositor stops producing frames and the window looks frozen — unresponsive to clicks and keys — even though the renderer stays alive. setupDarwinCompositorWatchdog polls the renderer for frame production and, on a sustained stall while the window is visible and unlocked, restarts the GPU process so Chromium rebuilds the display link. This replaces setupDarwinPaintRefresh, whose invalidate/resize nudges did not address the dead display link. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
64e01d8 to
6a5c345
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #741.
On macOS, locking the screen until the display sleeps can leave the Paseo
desktop window frozen after unlock — clicks and keypresses do not land —
even though the renderer and every process stay alive. It self-recovers
after a few minutes. Strongest repro: the Mac mini / external-display wake path.
Root cause: macOS display sleep can leave Chromium's GPU-process display
link — the vsync source that drives frame production — stuck on a stale
display. The compositor then stops producing frames, so the window looks
frozen while actually being alive. Restarting the GPU process makes Chromium
rebuild the display link, and frames resume.
Changes
setupDarwinCompositorWatchdog(packages/desktop/src/window/window-manager.ts)replaces the previous
setupDarwinPaintRefresh:requestAnimationFrame,bounded by a
setTimeoutso the probe resolves even when frame productionhas stopped).
not minimized, and the screen is unlocked — restarts the GPU process with
SIGKILL; Chromium relaunches it automatically.main.tswires it in;window-manager.test.tscovers theshouldRecoverFromFrameStalldecision logic;docs/development.mddocumentsthe gotcha. The previous
setupDarwinPaintRefreshonly nudged the window size /invalidated the surface, which does not address the dead display link.
Note on the earlier revision
An earlier version of this PR attributed the freeze to a renderer-side
history-sync cascade and changed five app-layer files. Diagnostic builds showed
the freeze is frame-production death in the GPU process, not renderer
main-thread starvation — so the app-layer changes were dropped and this PR now
carries only the GPU-watchdog fix.
Verification
occurred. The watchdog detected the frame-production stall, restarted the GPU
process once (no second attempt needed), and the window recovered — versus
the ~3-minute unmitigated freeze.
npx vitest run packages/desktop/src/window/window-manager.test.ts— 18 tests pass.npm run typecheck(all workspaces),npm run lint,npm run format:check— pass.Risk / compatibility
process.platform === "darwin"). No WebSocketor schema change.
unlocked; cooldown + attempt cap bound it.
powerMonitorlisteners are removed when the window closes.Test plan
interact — the window recovers within seconds instead of staying frozen.
when there is no real freeze.