Coalesce renderer visibility transitions - #100
Conversation
# Conflicts: # src/renderer/Thread.zig
📝 WalkthroughWalkthrough
ChangesRenderer updates
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant AppMailbox
participant App
participant Surface
participant RendererThread
participant Renderer
AppMailbox->>App: Drain messages and consume redraw retry
App->>Surface: Notify mailbox capacity is available
Surface->>RendererThread: Trigger retained visibility retry
RendererThread->>Renderer: Apply coalesced visibility transition
Renderer-->>RendererThread: Submit or defer regain render
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
| self.flags.cursor_blink_visible, | ||
| ) catch |err| | ||
| log.warn("error rendering on visibility regain err={}", .{err}); | ||
| self.drawFrame(false); |
There was a problem hiding this comment.
Synchronized Output Skips Redraw
When a hidden terminal is revealed while synchronized output mode is still enabled, updateFrame can return without rebuilding cells, but this path still calls drawFrame(false). Because that draw is not forced and setVisible(true) runs afterward, the reveal can present the old target instead of a fresh frame until another render-triggering event occurs.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/terminal/render.zig (1)
1789-1809: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider adding negative assertions for non-dirty rows.
Test 1 asserts
dirty[0]anddirty[3]are true but doesn't verify that rows 1, 2, and 4 remain clean. The existing "dirty state" test (line 1784-1785) checks both dirty and clean rows. Adding the same here would strengthen confidence that only the marked rows were rebuilt.💚 Suggested addition
try testing.expect(dirty[0]); try testing.expect(dirty[3]); + try testing.expect(!dirty[1]); + try testing.expect(!dirty[2]); + try testing.expect(!dirty[4]); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/terminal/render.zig` around lines 1789 - 1809, Add negative assertions to the “dirty rows accumulate before one render update” test, verifying that dirty flags for rows 1, 2, and 4 remain false after the update while rows 0 and 3 are true.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/renderer/Thread.zig`:
- Around line 627-643: drainMailbox currently rebuilds the frame on visibility
regain, while wakeupCallback then renders it again. Make drainMailbox return a
flag indicating successful regain rendering, have wakeupCallback skip
renderCallback when that flag is set, and add an integration assertion verifying
exactly one update and draw call.
---
Nitpick comments:
In `@src/terminal/render.zig`:
- Around line 1789-1809: Add negative assertions to the “dirty rows accumulate
before one render update” test, verifying that dirty flags for rows 1, 2, and 4
remain false after the update while rows 0 and 3 are true.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8454cf21-dced-4415-86d4-a6e992d0243f
📒 Files selected for processing (2)
src/renderer/Thread.zigsrc/terminal/render.zig
…y-pr # Conflicts: # src/renderer/Thread.zig
Backports cmux renderer visibility suspension to the pinned Ghostty lineage and coalesces rapid hide/show mailbox transitions. Hidden terminals retain dirty rows and rebuild once when revealed. Includes Zig coverage for visibility ordering, dirty-row accumulation, and full-redraw dominance. This dependency PR stays unmerged until the combined cmux tagged build is dogfood-approved.
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Summary by cubic
Coalesces renderer visibility changes, suspends hidden-frame rebuilds, and guarantees reveal draws exactly once with a confirmed submission. Adds optional, content‑free renderer activity callbacks and a reliable retry path when the app mailbox is full.
Refactors
VisibilityDrainState; hidden wakes skipupdateFrame.setVisible; retain the prepared frame if the app mailbox is full and retry after drain.App.redraw_retry_requestedand surfaces callSurface.appMailboxDrained()to trigger the retry.updateFrameanddrawFrame, returns draw results, and keeps prepared damage until draw commit (forces full redraw next draw if needed).New Features
ghostty_renderer_event_cbtoghostty.h; plumbed viaghostty_surface_config_s.renderer_event_cb, embeddedSurface.Options, andrenderer.Instrumentation.updateFrame/drawFrameon the renderer thread when a backend draw is attempted or an app‑thread submission is accepted; callback must be thread‑safe and non‑blocking.Written for commit c66c787. Summary will update on new commits.
Summary by CodeRabbit
New Features
Bug Fixes
Tests