feat: integrate the Linux bell with the desktop environment, and coalesce BEL floods#1637
Open
nikicat wants to merge 2 commits into
Open
feat: integrate the Linux bell with the desktop environment, and coalesce BEL floods#1637nikicat wants to merge 2 commits into
nikicat wants to merge 2 commits into
Conversation
…im#1616) On Linux the terminal bell now integrates with native DE attention mechanisms instead of only a synthesized 440 Hz tone: - `[bell] audio` accepts `"system"` (default on Linux) to play the freedesktop event-sound theme via libcanberra, respecting the user's sound theme, output routing, volume, mute and Do-Not-Disturb. It is loaded at runtime via dlopen, so there is no build-time dependency and it degrades gracefully when absent. `true`/`false` stay backwards compatible (legacy tone / off). - `[bell] urgency` (default true on Linux) sets the window urgency / attention hint (X11 WM_HINTS, Wayland xdg-activation) when the bell fires in an unfocused window, and clears it on focus-regain. - `[bell] notification` (default false) raises an org.freedesktop.Notifications notification for an unfocused window. The audio/urgency/notification config values use named enums rather than bare bools to avoid boolean blindness. The cpal tone moves into a new `bell` module alongside the libcanberra binding. Documents the new keys in the rio.5 man page. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`cat`-ing a binary file streams thousands of BEL (0x07) bytes. Each one emitted a `RioEvent::Bell`, which flooded the event loop and — on Linux — ran the libcanberra/NSBeep call synchronously on the window thread per byte, freezing the whole app and ringing constantly until the source process was killed. Two independent fixes: - Coalesce in the backend `bell()`: emit at most one bell per `bell_min_interval` (new `bell.min-interval` config, default 3s). This is the only place that can stop the per-byte event flood before it reaches the event loop. The window is far longer than any bell sound, so it never re-triggers mid-playback without assuming the sound length. - Move audio playback to a dedicated `rio-bell` worker thread; the window thread is never touched. Regression tests drive real BEL bytes through the parser into `bell()` and advance a deterministic mock clock (mock_instant, dev-dependency only; production keeps std::time::Instant via a cfg-gated alias) to prove the gate re-arms purely from elapsed time. A second test asserts the gate is per-terminal, so one noisy terminal can never silence the others. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
This bundles two related bell changes. They are not strictly atomic, but the second builds directly on the first, so they are submitted together.
1. Integrate the Linux bell with the desktop environment (closes #1616)
On Linux the terminal bell now integrates with native DE attention mechanisms instead of only a synthesized 440 Hz tone:
[bell] audioaccepts"system"(default on Linux) to play the freedesktop event-sound theme via libcanberra, respecting the user's sound theme, output routing, volume, mute and Do-Not-Disturb. libcanberra is loaded at runtime viadlopen, so there is no build-time dependency and it degrades gracefully when absent.true/falsestay backwards-compatible (legacy tone / off).[bell] urgency(defaulttrueon Linux) sets the window urgency / attention hint (X11WM_HINTS, Waylandxdg-activation) when the bell fires in an unfocused window, and clears it on focus regain.[bell] notification(defaultfalse) raises anorg.freedesktop.Notificationsnotification for an unfocused window.The audio/urgency/notification config values use named enums rather than bare bools. The cpal tone moves into a new
bellmodule alongside the libcanberra binding. The new keys are documented in therio.5man page.2. Coalesce BEL floods so a binary
catcan't freeze the appcat-ing a binary file streams thousands of BEL (0x07) bytes. Each one emitted aRioEvent::Bell, which flooded the event loop and — on Linux — ran the libcanberra/NSBeepcall synchronously on the window thread per byte, freezing the whole app and ringing constantly until the source process was killed.bell(): emit at most one bell perbell_min_interval(new[bell] min-intervalconfig, default3000ms). This is the only place that can stop the per-byte event flood before it reaches the event loop. The window is far longer than any bell sound, so it never re-triggers mid-playback without assuming the sound's length.rio-bellworker thread, so the window thread is never blocked by audio I/O.Tests
bell()and advances a deterministic mock clock (mock_instant, a dev-dependency only — production keepsstd::time::Instantvia a one-linecfg-gated alias) to prove the gate re-arms purely from elapsed time. It fails (50 000 bells) without the gate.🤖 Generated with Claude Code