Skip to content

apprt: add output_activity action for throttled IO-path activity heartbeat - #3

Closed
onliner10 wants to merge 2 commits into
thdxg:mainfrom
onliner10:output-activity-action
Closed

apprt: add output_activity action for throttled IO-path activity heartbeat#3
onliner10 wants to merge 2 commits into
thdxg:mainfrom
onliner10:output-activity-action

Conversation

@onliner10

Copy link
Copy Markdown

What

Adds GHOSTTY_ACTION_OUTPUT_ACTIVITY: a heartbeat emitted from the IO path (throttled to 500ms, reusing the existing cursor-reset throttle idiom) whenever the pty produces output, carrying the current scrollbar geometry. Unlike scrollbar, which comes from the renderer and stops while occluded, this fires regardless of visibility. Purely additive — appended last in both Action.Key and ghostty_action_tag_e, no existing behavior changes.

Why

macterm needs an occlusion-independent output signal to drive its per-tab activity indicator — for minimized/backgrounded tabs, and for raw-mode TUIs (editors, AI coding CLIs) that redraw in place with no scrollback growth. scrollbar can't cover either case.

Embedder-only API addition, no user-facing config surface.

Testing

Built locally, swapped into a macterm debug build, confirmed end-to-end (instrumented logging) that the action fires and reaches the app layer while occluded and during raw-mode in-place redraws.

AI disclosure

Written with Claude Code, driven by me — I designed the throttle/routing approach, reviewed the full diff, and understand its interaction with renderer occlusion and the surface mailbox.

Note

No existing issue — this is a fork-specific embedder API addition, not a user-facing feature. Happy to adjust process if preferred.

github-actions Bot and others added 2 commits July 7, 2026 09:36
Single squashed commit of all thdxg/ghostty customizations on top of
upstream ghostty-org, so the downstream delta is always exactly one
commit ahead. Regenerated automatically by sync-upstream.yml.
…tbeat

Add GHOSTTY_ACTION_OUTPUT_ACTIVITY, a throttled heartbeat emitted from the
terminal IO path whenever the child/pty produces output. It carries the
current scrollbar geometry (ghostty_action_scrollbar_s) and is delivered via
the surface mailbox -> app-tick -> performAction track, not the renderer
thread. Unlike the renderer-track scrollbar action, this keeps firing while
the surface is occluded (the renderer parks on occlusion), so embedders can
drive an activity indicator for in-place TUI redraws and backgrounded tabs.

Throttled to at most once per 500ms in Termio.processOutputLocked, reusing
the cursor-reset throttle idiom: the Instant compare runs per pty chunk while
the scrollbar read only happens when emitting. The action is appended last in
both the Zig Action.Key enum and the C ghostty_action_tag_e so existing tag
values are unchanged.
@onliner10
onliner10 force-pushed the output-activity-action branch from 09a367f to 586363e Compare July 7, 2026 09:51
@thdxg
thdxg force-pushed the main branch 9 times, most recently from 2e36519 to 3a6478a Compare July 14, 2026 13:28
@thdxg

thdxg commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Thanks for this, @onliner10 — the change itself is exactly right, and I've verified end to end that it's the signal Macterm needs: an occlusion-independent output heartbeat that the render-track scrollbar/RENDER path can't provide for backgrounded tabs or in-place TUI redraws.

The catch is purely mechanical, not about the code. This fork stays exactly one commit ahead of ghostty-org/ghostty: sync-upstream.yml rebuilds main every morning by git reset --hard upstream/main, re-laying a fixed file list plus every .github/downstream/*.patch. Anything landed as a raw source merge — rather than as a committed patch — gets silently dropped on the next sync (and assert-no-drift.yml would flag the drift). This PR is also currently built on the old whole-tree-squash base, so it shows ~165 changed files and reads as un-mergeable.

So I've carried the change forward the way the command-wrapper patch is maintained:

  • Reformatted your commit as .github/downstream/0002-output-activity.patch — verified it applies cleanly against current upstream (git apply --check, both standalone and after 0001).
  • Wired the Macterm consumer (GHOSTTY_ACTION_OUTPUT_ACTIVITY → sustain-only activity heartbeat; primary source for remote panes).
  • Added TerminalExecutionTracker tests pinning the sustain-only semantics (output keeps a running spinner alive but never starts or resurrects it).

Full credit is preserved — the patch keeps your authorship on the commit. Given that, I'm going to land the change via the 0002 patch and close this PR — nothing wrong with your work, it's just the delivery format this fork's sync requires. Really appreciate the clean, well-documented contribution and the AI-disclosure note.

@thdxg thdxg closed this Jul 14, 2026
@onliner10

onliner10 commented Jul 16, 2026 via email

Copy link
Copy Markdown
Author

@thdxg

thdxg commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Do I understand it right that you also make the changes for macterm to actually use this signal?

Yes!

Btw should you need any help on macterm development, feel free to reach me out directly!

Thanks! Truly appreciated 😊

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.

2 participants