Add capture_hidden option to filter peak monitoring for hidden items - #75
Closed
HoneyHazard wants to merge 9 commits into
Closed
Add capture_hidden option to filter peak monitoring for hidden items#75HoneyHazard wants to merge 9 commits into
HoneyHazard wants to merge 9 commits into
Conversation
Lets a user hide individual nodes/devices from their own running instance with the t key (toggle). Hidden state is purely local: never persisted to disk, never synced to other running instances - that's covered by a planned follow-up perma-hide tier (Ctrl+t). - Hidden items sink to the bottom of their list, in a stable sort that otherwise preserves the existing object_serial order - both the visible group and the hidden group keep their relative order. - Excluded from peak capture: start_capture() gates on hidden_instance the same way it already gates on lazy_capture's visible_objects, and toggling hidden explicitly stops/resumes an in-flight capture immediately rather than waiting for the next eligibility event. - New row_hidden theme key, patched onto a hidden row's text spans (title, target, volume%, and Configuration tab's device/profile) using the same Style::patch() no-op-by-default mechanism as the rest of the theme system. - New hidden_instance char_set key (default "[hide] ") prepended to a hidden item's title, so hidden items are identifiable even with row_hidden left unset - built-in char_sets and wiremix.toml's docs suggest an emoji alternative (e.g. "🙈 ").
Two fixes to the per-instance hide feature:
- row_hidden defaulted to an empty style in every built-in theme, so the
only visual difference for a hidden row was its char_set prefix
("[hide] "/emoji) - easy to miss at a glance. default now dims it with
DarkGray, nocolor with the DIM modifier (matching that theme's existing
"dim = inactive" convention elsewhere). plain is left alone on purpose -
it's styled nowhere else either, relying entirely on the prefix text.
- Hiding the selected item left the selection pinned to it. Since hidden
items sink to the bottom of the list, this meant the cursor stayed on a
now-relocated, visually de-emphasized row instead of following what the
user was actually looking at. ObjectList::release_hidden_selection()
moves the selection to whatever comes right after the hidden item in
the list's current (pre-sink) order, falling back to whatever comes
before it if it was last, or to no selection at all if it was the only
item. Unhiding intentionally keeps the selection where it is - the user
is still looking at that item, there's nothing to release.
Extends the per-instance hide from the previous branch with a second, independent tier: Ctrl+t hides/shows the selected item durably - saved to disk, and rediscovered against live nodes on every future launch (including other already-running instances that reload the same file, though nothing here makes that reload happen live yet - see the follow-up branch for cross-instance sync via PipeWire Metadata). - Items are identified by node.name via a new MatchCondition::from_node_name() constructor, reusing the existing [[filters]] matching engine rather than raw object IDs, which don't survive a restart. - New src/hidden_state.rs module handles load/save of a small $XDG_STATE_HOME/wiremix/hidden.toml file (mirroring the existing $XDG_CONFIG_HOME resolution for the main config file), with an atomic temp-file-then-rename write. - Adds Serialize support to MatchCondition/MatchValue/PropertyKey (previously deserialize-only, since nothing needed to write a matcher back out before this), implemented as the exact inverse of their existing FromStr parsing. - Sort order becomes three-tier: visible, then instance-hidden, then permanently-hidden at the very end - both hidden groups keep their own relative order. - Reuses the row_hidden theme key from the previous branch (same faint-text treatment for both hidden tiers) and adds a second char_set key, hidden_permanent (default "[perm-hide] "), so the two tiers stay visually distinguishable by their title prefix even when styled identically. - Capture gating gate is evaluated directly against the durable matcher list, not a cached per-object-ID set - the initial flood of capture-eligibility events on startup is handled before the first opportunity to recompute that cache, so relying on the cache alone let an already-permanently-hidden node start capturing again on every fresh launch (caught via live pw-dump verification, not the unit tests, which mock past the real startup ordering).
Watches the permanent-hide state file's directory for changes made by other wiremix instances (e.g. another instance's own Ctrl+t), so the change takes effect immediately everywhere instead of only on each instance's next restart. Uses inotify on the directory rather than the file itself, since HiddenState::save() writes via temp file + rename and a direct file watch would go stale after the first rename. Linux-only, gated behind target_os = "linux" with a no-op fallback elsewhere, matching wiremix's existing de facto Linux-only scope (unconditional nix dependency, no PipeWire port to other platforms). This replaces an earlier PipeWire-Metadata-based approach for live sync that was abandoned after a production incident; this design has no PipeWire object creation/lifecycle involved at all, only local filesystem event watching reusing the same directory HiddenState::save() already writes to.
Same fix as the per-instance hide/show branch, applied to Ctrl+t: hiding the selected item now moves the selection to whatever's next in line (falling back to the previous item, or no selection at all if it was the only one) instead of leaving it pinned to an item that's about to sink to the bottom of the list. Reuses release_hidden_selection(), already added for the instance-hide case. Un-hiding still keeps the selection where it is.
Shorter and reads more clearly at a glance than "perm-hide" - "[hide]" (instance) vs "[HIDE]" (permanent) distinguishes the two by case alone rather than needing an extra word.
Hiding an item (per-instance or permanently) currently always stops its peak capture unconditionally, with no way to opt out. That's a hardcoded behavior, not a configurable one - and CPU/monitoring concerns aside, some users may want hidden items to keep reporting levels exactly like any other item, since hiding is about decluttering the visible list, not necessarily about suppressing monitoring. Adds capture_hidden: bool (default true), also available as --capture-hidden/--no-capture-hidden on the command line. It's a filter layered on top of the existing capture-eligibility rules (lazy_capture, filters, etc.), never a replacement for them - when true (the default), hidden items are captured under exactly the same rules as regular ones, reproducing today's non-hidden-item behavior for hidden items too. When false, hidden items are excluded from capture in addition to whatever else already excludes non-hidden items, matching the previous hardcoded-exclusion behavior exactly. - start_capture()'s existing hidden_instance/hidden_permanent checks are now gated behind !capture_hidden instead of always applying. - ToggleHiddenInstance/ToggleHiddenPermanent's explicit stop_capture() calls on hide (and the resuming start_capture() calls on unhide) are similarly gated - important not just for correctness under the new default, but to avoid double-starting an already-running capture stream when capture_hidden is true and hiding never stopped it in the first place. - apply_file_hidden_state_change()'s stop sweep (triggered by another instance's hidden-state file changing) is gated the same way. - When monitoring actually is suspended for a hidden item (hidden + capture_hidden = false), NodeWidget now leaves the peak meter completely blank instead of drawing the usual inactive-looking placeholder over a stream that will never receive samples, which otherwise reads as broken rather than intentionally off. Stacked on top of the hide-items-permanent branch/PR - this is a followup to that work, not a standalone feature. Tested: cargo test --release (181/181 passing, including 5 new tests covering both capture_hidden = true/false for instance-hide, permanent-hide, fresh eligibility events, and the file-sync path, plus a rendering test confirming the meter goes blank only when monitoring is actually suspended), cargo fmt --check, cargo clippy -- -D warnings, and cargo doc all clean.
HoneyHazard
force-pushed
the
hide-items-capture-filter
branch
from
August 9, 2026 09:41
3151f40 to
5e43606
Compare
HoneyHazard
added a commit
to HoneyHazard/wiremix
that referenced
this pull request
Aug 9, 2026
Author
|
Folding this into the stack it depends on instead of keeping it separate: |
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.
That being said, I hope these can be helpful and useful additions that users could appreciate.
Follow-up to the hide-items-permanent PR (#72, which itself follows #71) - stacked on top of that branch, not a standalone feature.
Hiding an item (per-instance with
t, or permanently withCtrl+t) currently always stops its peak capture unconditionally, with no way to opt out. That's a hardcoded behavior, not a configurable one - hiding is about decluttering the visible list, and some users may want hidden items to keep reporting levels exactly like any other item rather than having that tied to visibility.On naming:
t/Ctrl+twere chosen as a mnemonic for "toggle hide," not "toggle visibility" - deliberately, since this PR is exactly the case where hiding an item and suspending its monitoring are two separate, independently-toggleable things rather than one and the same. "Hide" names the primary, always-on effect (removed from the visible list);capture_hiddenis what optionally layers a monitoring effect on top.Adds
capture_hidden: bool(defaulttrue), also available as--capture-hidden/--no-capture-hiddenon the command line:lazy_capture,filters, etc.), never a replacement for them.true(the default), hidden items are captured under exactly the same rules as regular ones - reproducing today's non-hidden-item behavior for hidden items too, so nothing changes unless you opt in.false, hidden items are excluded from capture in addition to whatever else already excludes non-hidden items - matching the previous hardcoded-exclusion behavior exactly.capture_hidden = false), the peak meter is left completely blank instead of drawing the usual inactive-looking placeholder over a stream that will never receive samples - that placeholder otherwise reads as broken rather than intentionally off.Both instances show the same
[hide] Lavf61.7.102: recorditem, hidden witht. Left: defaultcapture_hidden = true- the meter keeps reporting real levels. Right:--no-capture-hidden- the meter is blank because the capture stream itself is stopped.New config key (optional, no-op when unset):
Also available as
--capture-hidden/--no-capture-hiddenon the command line.Tested:
cargo test --release: 181/181 passing, including 5 new tests covering bothcapture_hidden = true/falsefor instance-hide, permanent-hide, fresh eligibility events, and the cross-instance file-sync path, plus a rendering test confirming the meter goes blank only when monitoring is actually suspendedcargo fmt --check/cargo clippy -- -D warnings/cargo doc(matching this repo's CI): all cleancapture_hiddenleft at its default keeps the peak meter animating; setting--no-capture-hiddenblanks the meter for hidden items immediately and un-hiding resumes itDrafted with AI assistance (Claude); reviewed by me before opening. Left as a draft while I finish going through it - not requesting review yet.