Skip to content

fix(notifications, terminal): desktop notification delivery and rendering fixes - #49

Merged
nakulbh merged 2 commits into
mainfrom
fix/ui-thread-latency
Jul 31, 2026
Merged

fix(notifications, terminal): desktop notification delivery and rendering fixes#49
nakulbh merged 2 commits into
mainfrom
fix/ui-thread-latency

Conversation

@nakulbh

@nakulbh nakulbh commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Summary

  • Notifications weren't visibly working. OSC-based notifications (e.g. "Claude is waiting for your input") were fully designed and documented (docs/guide/16-notifications.md, docs/guide/07-osc-notifications.md) but never actually wired up — TerminalPane fed PTY bytes to the terminal grid only. Wired OscScanner through PaneNodeWorkspaceWorkspaceManagerRmuxApp, with a targeted filter so iTerm2/ConEmu progress-bar OSC 9 sequences (OSC 9;4;<state>[;<percent>]) don't produce junk notifications (the reason this was disabled previously).
  • macOS notifications landed in Notification Center but never popped up. mac-notification-sys silently posts as com.apple.Finder when the binary isn't in a registered bundle (any dev build) — delivery "succeeds" but no banner shows, since most users have muted Finder's routine alerts. Now claims rmux's own identity (matching scripts/install.sh's bundle id), falling back to com.apple.Terminal. Also sets appname/icon on Linux so notifications group under "rmux".
  • Scrambled text after sleep/wake (macOS + Linux). Our per-glyph Arc<Galley> cache bakes in mesh UVs pointing into egui's font texture atlas. egui rebuilds that atlas whole on DPI change, fill-ratio overflow, or — in practice — GPU context recreation after OS suspend/resume. Cached galleys kept pointing at the old atlas packing, painting garbage from wherever the new atlas happened to repack. Now tracks the atlas's Arc identity and drops the glyph cache whenever it changes, for any reason, on any platform.
  • Full-screen TUIs (nvim, lazygit, btop) leaving a gap below/beside their content. Row height was a flat font_size * 1.15 guess, ~13-15% taller than JetBrains Mono's real line height, so rmux consistently undercounted how many rows/cols fit the pane. A TUI queries its size once at startup and only redraws on SIGWINCH, so it latched onto the undercounted geometry. Now measures the font's real row height; the original guess's actual job (keeping block/box-drawing TUI art tiling without seams) is handled directly by rendering those characters as geometry sized to the cell — already true for block elements, now extended to the common single-line box-drawing set (─│┌┐└┘├┤┬┴┼).

Test plan

  • cargo clippy --workspace --all-targets — clean
  • cargo test --workspace — all passing (377 tests, several new: OSC progress-bar filtering, glyph-cache atlas invalidation, box-drawing geometry classification)
  • Launched the app, restored a real multi-workspace session, fired a notification via rmux-cli notification create — no panics/warnings in logs
  • Would benefit from a manual check on your machine: open nvim in a pane and confirm it fills to the edges, and check a real notification pops up as a banner (not just Notification Center history)

🤖 Generated with Claude Code

nakulbh and others added 2 commits August 1, 2026 04:09
…livery

Desktop notifications reached Notification Center on macOS but never
popped up a banner, and OSC-triggered notifications (e.g. "Claude is
waiting for your input") never fired at all, even though the scanner
and app-side plumbing for them were designed and documented
(docs/guide/16-notifications.md, docs/guide/07-osc-notifications.md)
but never actually wired together — TerminalPane fed PTY bytes to the
terminal grid only, dropping them on the floor as far as notifications
were concerned.

- rmux-terminal/osc.rs: OSC 9 is overloaded — iTerm2/ConEmu also use it
  for progress bars (`OSC 9;4;<state>[;<percent>]`), which is why this
  was disabled previously (produced junk notifications like "4;0;").
  Add a targeted filter that recognizes and drops only that exact
  shape, so real notification text is unaffected.
- rmux-app: give TerminalPane its own OscScanner over the same PTY
  bytes it feeds to TermState (scanning never mutates the stream), and
  thread completed notifications up through PaneNode -> Workspace ->
  WorkspaceManager -> RmuxApp, tagged with (workspace_id, pane_id), to
  the same NotificationManager::add() path the CLI's
  `notification.create` already used.
- notifications/mod.rs: on macOS, mac-notification-sys silently posts
  every notification as com.apple.Finder when the running binary isn't
  inside a registered bundle (i.e. any dev/debug build) — delivery
  "succeeds" so it lands in Notification Center's history, but no
  banner ever animates, since most users have long muted Finder's
  routine trash/eject alerts. Explicitly claim rmux's own identity
  (matching the bundle id scripts/install.sh registers), falling back
  to Terminal's when rmux.app was never installed. Also set
  appname/icon on Linux so notifications group under "rmux" instead of
  a blank/PID-derived name.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…he pane

Two separate rendering bugs, both cross-platform (macOS + Linux) since
neither depends on OS-specific code paths:

- Scrambled/garbled text after resume from sleep: our own per-glyph
  Arc<Galley> cache holds mesh vertices with UV coordinates baked in
  for egui's font texture atlas. egui rebuilds that atlas whole (DPI
  change, max_texture_side change, or simply filling past ~80% over a
  long session) — and in practice, the GPU context getting recreated
  after the OS suspends/resumes triggers the same rebuild. Our cached
  galleys kept pointing at the old atlas's packing, so painting them
  against the freshly repacked (differently laid out) atlas sampled
  whatever now happened to sit at those old coordinates: scrambled
  glyphs. Fix: track the atlas's Arc identity and drop the whole glyph
  cache whenever it changes, for any reason, on any platform — no
  sleep/wake-specific detection needed.

- Full-screen TUIs (nvim, lazygit, btop, etc.) leaving a gap below and
  sometimes beside their content: row height was a flat `font_size *
  1.15` guess, chosen to keep block-element TUIs (LazyVim's logo)
  looking tight. That guess ran ~13-15% taller than JetBrains Mono's
  real line height, so the cols/rows we told the PTY (and thus the
  TUI) was consistently undercounted versus the pane's actual pixel
  size. A full-screen TUI queries its size once at startup and only
  repaints on SIGWINCH, so it latched onto geometry smaller than the
  pane and never grew to fill it. Fix: measure the font's real row
  height instead of guessing. The original guess's actual job — making
  sure adjacent rows of block-drawing / box-drawing characters tile
  without seams — is now handled directly by rendering those
  characters as geometry sized to the cell (already true for block
  elements; extended here to the common single-line box-drawing set:
  ─│┌┐└┘├┤┬┴┼, used by nvim splits, nvim-tree, lazygit, btop borders),
  so it no longer depends on how a specific font's glyphs sit inside
  its own line metrics.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 31, 2026 22:40

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@nakulbh
nakulbh merged commit 5ba1b6a into main Jul 31, 2026
6 checks passed
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