Fix tray menu desync and Steam lightbar conflicts; gate v2 revokes pre-gate fds#3
Merged
Merged
Conversation
…ted udev nodes chmod alone cannot gate a pad an application already holds: Steam Input opens every controller's hidraw node on connect and its surviving fd kept reading the pad (double input) and writing output reports (lightbar firmware-latched dark, immune to kernel LED writes until re-probe). Gate v2 keys the gate by HID_UNIQ instead of a volatile node: - marker files under /run/controller-manager/gated (tmpfs: reboots fail-open) - 71-controller-manager.rules: gated hidraw nodes are BORN with MODE 0000 and without the uaccess tag (placed between 70-uaccess and 73-seat-late, otherwise the seat ACL would tunnel through MODE 0000) - driver unbind/bind on gate transitions revokes every open fd and resets the DualSense lightbar latch; strictly transition-only to avoid rebind loops with the daemon's re-asserts; 'rearm' rebinds without gating - block-node/restore-node keep the v1 chmod path for uniq-less pads
…+ resting-blue integration Menu (Issue #2, verified live on GNOME): the appindicator host caches item properties per dbusmenu id and misses reused ids across structural changes (separator->radio after a connect), leaving entries stuck disabled while the daemon serves enabled=true. The model is now built once per state change and cached (GetLayout/GetGroupProperties/GetProperty/Event answer from one snapshot, so clicks can no longer be misrouted by a shifting id map); structural changes allocate fresh ids from a monotonic counter (Quit keeps its constant id), display-only changes keep ids and go out as ItemsPropertiesUpdated deltas. Manager side of gate v2: gate before grabbing, re-resolve the renumbered nodes afterwards (_refresh_nodes), stay gated across reconnects (rebind no longer restores), and in ps5-native watch the pad's hidraw holders — when the last one exits, rearm the pad (lightbar latch) and repaint the resting blue. Scan now ignores Sunshine/inputtino virtual pads (synthetic phys / '(virtual)' names), identical uniq-less pads are kept apart via phys, and a dead remapper thread on a present pad re-asserts its mode (sub-poll BT blips). Unit tests cover the id model and the new reconcile branches.
… MODE assignment Field-verified leak: steam-devices ships 71-sony-controllers.rules, which runs after 71-controller-manager.rules (alphabetical within the same number) and re-adds MODE 0660 + the uaccess tag for DualSense hidraw. The reborn node came back 0660 with a seat ACL, Steam/games reopened it in a gated mode and repainted the lightbar (brief green, then stomped). - rename the rule to 72-: after every 71-*-controllers rule, still before 73-seat-late turns the uaccess tag into the seat ACL - MODE:=/GROUP:= final assignments so no later rule can override them (TAG-= has no final form; the 72- ordering is what protects it) - helper re-chmods the reborn nodes after the rebind as belt and braces (also zeroes the ACL mask should an ACL ever leak through again) - install.sh migrates: installs 72-, removes a stale 71- from earlier installs, reloads udev
Field logs: switching to ps5-native rebinds the driver (gate restore); ~6 s later Steam reopens the reborn hidraw node — it enumerates pads even with PlayStation support disabled — and writes its defaults ONCE, stomping the just-painted resting blue. A second click on the already-active mode 'fixed' it because that path rebinds nothing, so nobody reopened and the repaint kept the last word. watch_holders now classifies holder-set deltas instead of a boolean: releasers (game exit) rearm + repaint as before; new holders inside a 20 s settle window after a gate transition are reopen noise and get outlasted by one delayed repaint; new holders outside the window are a deliberate game start — hands off, pending repaints cancelled. apply_mode opens the settle window after every gate transition.
NicolasPogorzelski
added a commit
that referenced
this pull request
Jul 5, 2026
The overview still described the v1 chmod-only gate (single helper, 'restores to 666') and a menu 'rebuilt on every change'; the verify runbook checked the pre-switch hidraw node, which gate v2's driver rebind renumbers, and expected hard-coded 666 permissions where distribution rules now set the open mode + seat ACL. Both now match the shipped design: identity-keyed gate (marker + udev-born-gated nodes + rebind), resting-colour policy, cached menu model with never-recycled ids, phys identity fallback and the Sunshine exclusion. Roadmap: 2026-07-05 fixes are hardware-verified and merged (PR #3).
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.
Fixes #2.
Field bugs and verified root causes
Tray menu items stuck disabled / clicks dead after reconnect churn (Tray menu clicks stop reaching the daemon after reconnect churn (Plasma SNI/dbusmenu) #2).
Verified live: the daemon served
enabled=trueover D-Bus while the GNOMEappindicator host (desktop is GNOME, not Plasma as the issue hypothesised)
rendered the same item disabled. The host caches item properties per
dbusmenu id and misses reused ids across structural changes
(separator→radio after a connect). Fix: cached menu model, never-recycled
ids, ItemsPropertiesUpdated deltas. Decision: docs/decisions/tray-menu-model.md.
DualSense lightbar dark despite correct kernel LED state. Steam Input
opens every pad's hidraw node on connect; the fd survives the chmod gate
and Steam firmware-latches the lightbar off ('light out' setup flag) —
kernel LED writes then change nothing until re-probe. Fix: gate v2 —
identity-keyed markers, udev-born-gated nodes (72- rule; must outrank the
71-*-controllers rules from steam-devices, field-verified), driver rebind
to revoke fds and reset the latch. Decision: docs/decisions/hidraw-gate.md.
Resting colour policy (ps5-native). Holder-set watching: games own the
lightbar while they hold the pad; releasers trigger rearm + repaint;
Steam's post-rebind reopen (it enumerates even with PlayStation support
disabled and writes defaults once) is outlasted by a delayed repaint.
Decision: docs/decisions/steam-coexistence.md.
Also: Sunshine/inputtino virtual pads excluded from the scan, identical
uniq-less pads kept apart via phys, remapper liveness re-assert, unit tests
for the menu id model and new reconcile branches (50 assertions).
Verification on hardware
(Steam + Lutris/Proton titles)
ps5-native; titles without it use the Xbox mode as intended