Skip to content

macOS: reset fDisplayLinkRunning when releasing CVDisplayLink on hide#305

Open
bumfo wants to merge 1 commit into
HumbleUI:mainfrom
bumfo:fix/displaylink-running-state-on-hide
Open

macOS: reset fDisplayLinkRunning when releasing CVDisplayLink on hide#305
bumfo wants to merge 1 commit into
HumbleUI:mainfrom
bumfo:fix/displaylink-running-state-on-hide

Conversation

@bumfo
Copy link
Copy Markdown
Contributor

@bumfo bumfo commented May 11, 2026

Bug

On macOS, after Window.setVisible(false)Window.setVisible(true), the window appears frozen — no paint, no animation, no EventFrame ever fires. requestFrame() is a no-op until the window is toggled once more.

Root cause

WindowMac::setVisible(false) releases the CVDisplayLink and zeroes fDisplayLink, but doesn't clear fDisplayLinkRunning. The next setVisible(true) creates a fresh link, but requestFrame() checks if (fVisible && !fDisplayLinkRunning) — the stale true short-circuits the CVDisplayLinkStart call, so the new link is never started.

Regression history

The reset was unnecessary before 5cdda76 (macOS: Do not stop cvdisplaylink, 0.4.18) because displayLinkCallback used to clear the flag itself whenever a tick fired with no pending frame. That cleanup is commented out now, so setVisible(false) is the only remaining place to clear it. Affected versions: 0.4.18 through 0.4.24.

Repro

App.start(() -> App.runOnUIThread(() -> {
    Window w = App.makeWindow();
    w.setEventListener(e -> { /* paint on EventFrame */ });
    w.setContentSize(400, 300);
    w.setVisible(true);
    // ... later, on user action:
    w.setVisible(false);
    // ... and later again:
    w.setVisible(true);
    w.requestFrame();  // No EventFrame is dispatched — window never repaints.
}));

Fix

Set fDisplayLinkRunning = false alongside fDisplayLink = 0 when releasing the link in setVisible(false). One line.

setVisible(false) releases the CVDisplayLink and zeroes fDisplayLink,
but doesn't clear fDisplayLinkRunning. After the next setVisible(true)
creates a fresh link, requestFrame() finds the stale flag still set
and skips CVDisplayLinkStart — the new link is never started, no
displayLinkCallback fires, no EventFrame is dispatched, and the window
appears frozen (no paint, no animation) until the user toggles
visibility again.

The reset was unnecessary before 5cdda76 ("macOS: Do not stop
cvdisplaylink", 0.4.18) because displayLinkCallback used to clear the
flag whenever it observed a quiet tick. That callback path is commented
out now, so setVisible(false) is the only place left to clear it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant