Skip to content

fix: idle-inhibit Steam games matching steam_app_* - #9667

Open
kvnloo wants to merge 2 commits into
omacom:quattrofrom
kvnloo:fix/9636-steam-app-idle-inhibit
Open

kvnloo wants to merge 2 commits into
omacom:quattrofrom
kvnloo:fix/9636-steam-app-idle-inhibit

Conversation

@kvnloo

@kvnloo kvnloo commented Sep 1, 2026

Copy link
Copy Markdown

Closes #9636

Hyprland FullMatchs class regexes, so literal steam never matches steam_app_<id>. Keep the client float+idle_inhibit rule and add steam_app_.* idle_inhibit fullscreen without float.

test/shell.d/steam-idle-inhibit-test.sh PASS on 346f98a5.

@omarchybot

Copy link
Copy Markdown
Collaborator

Reviewed on a disposable VM running Hyprland 0.56.2, with this branch's own tree loaded by the compositor rather than read as text. The matcher is correct and it fixes #9636.

Each window put fullscreen and read back from hyprctl clients -j:

class inhibitingIdle while fullscreen
steam_app_2622380 (the class in the report) true
steam_app_battlenet (umu/GE-Proton, per default/hypr/apps/battlenet.lua) true
steam (the client, from the existing rule on line 1) true
gamescope false

Windowed, every one of them reports inhibitingIdle: false, which answers the worry about the opposite failure: idle_inhibit = "fullscreen" inhibits only while a matching window is actually fullscreen, so this cannot leave a machine awake because Steam is sitting open in the background.

./test/shell.d/steam-idle-inhibit-test.sh passes 3 of 3 on the worker.

One finding, low severity but worth closing before this lands: the test is comment-blind, and will stay green on a change that removes the rule. Its assertions search the raw file text without anchoring to the start of a line, so commenting the rule out —

-- o.window("steam_app_.*", { idle_inhibit = "fullscreen" })

— still passes 3 of 3. Verified by mutation on the worker. Anchoring to line starts, with /^o\.window\(/m, closes it. Alongside that, the third assertion is redundant: the first already requires the rule's table to contain idle_inhibit and nothing else, so { float = true, idle_inhibit = "fullscreen" } fails assertion one before assertion three ever sees it.

The added comment says "Games are steam_app_<id>", which holds for Proton and umu titles rather than universally: a native game that sets its own executable-derived class, and a game behind a nested gamescope session where Hyprland sees the outer surface with app id gamescope, are both missed. Both are outside the reported bug, and #9651 misses them identically.

Nothing was pushed to this branch. #9651 fixes the same issue with the pattern ^steam_app_, which full matching reduces to the literal class steam_app_ and which measured as a no-op for steam_app_2622380 on the same worker; which branch lands is the maintainer's call.

Reviewed by Claude Opus 5 in Claude Code, with a second opinion from Codex at xhigh reasoning. The comment-blind test was Codex's finding rather than something already concluded, and it was then verified by mutation on the worker. Codex also agreed with the matcher analysis, and there its independence is not guaranteed.

@kvnloo

kvnloo commented Sep 4, 2026

Copy link
Copy Markdown
Author

Follow-up: steam idle-inhibit test now anchors o.window rules to line start (/^…/m) so a commented-out rule fails. Addresses omarchybot comment-blind finding.

@omarchybot

Copy link
Copy Markdown
Collaborator

Re-reviewed at 8cf7ed26. The anchoring fix does what it claims, and rather than resting on the previous pass I went back to a compositor to answer the over-matching and leak questions by measurement.

The delta. Verified by mutation on a disposable Hyprland 0.56.2 worker running this branch's own tree: with the rule commented out as -- o.window("steam_app_.*", ...), the test now fails (0 passed, 1 failed), where at 346f98a5 the same mutation passed 3 of 3. The comment-blind finding from the last pass is closed. At head, ./test/shell.d/steam-idle-inhibit-test.sh passes 3 of 3 and ./test/cli is 116 ok, 0 not ok, exit 0.

Over-matching. Each class spawned alone and fullscreened, inhibitingIdle read back from hyprctl clients -j:

class inhibitingIdle when fullscreen
steam_app_2622380 true
steam_app_battlenet true
steam_app_ (bare) true
steam_app_1234_extra true
xsteam_app_1 false
notsteam_app_9 false
steamwebhelper false
steam true, from the pre-existing rule on line 1

xsteam_app_1 and notsteam_app_9 staying false is the anchoring answer: Hyprland full-matches, so steam_app_.* is prefix-precise without a literal ^. steamwebhelper staying false is the one that matters — that is the CEF process behind the store, the library and the in-game overlay, and it gains nothing from this rule. Big Picture reportedly arrives as class steam and so is covered by line 1 rather than by this change, though I could not run real Steam on the worker to confirm that.

Release. Measured rather than reasoned:

  • Fullscreen window moved to a workspace that is not visible: inhibitingIdle drops to false. Moved back: true again.
  • Moved to special:scratchpad: false.
  • SIGKILL on the client, standing in for a crash: window gone, nothing inhibiting.
  • hyprctl reload while inhibiting: correctly re-established. Reload after the window closed: nothing inhibiting.
  • End to end, with idle.screensaver cut to 8s and no input for 30s: with the game fullscreen the shell never idled (idle: false, screensaverStarted: false throughout), and with the window closed the screensaver fired within 10s. So this fixes Screensaver fires over fullscreen Steam games every 150s: the idle_inhibit rule can never match a game #9636, and nothing latches.

There is structurally nothing to leak. idle_inhibit is the repository's one mechanism for this, already used by default/hypr/apps/geforce.lua:1, moonlight.lua:1, retroarch.lua:5 and system.lua:57, and the shell side is a single IdleMonitor { respectInhibitors: true } at shell/plugins/services/idle/Service.qml:254 that delegates to the compositor. This rule reuses that path rather than adding a second one.

Two residual notes on the test, both low, neither blocking. Both verified by mutation on the worker:

  • A Lua block comment still hides the rule from the test. Wrapping line 3 in --[[ and ]] disables it and leaves 3 of 3 green, because the rule's text still begins a line.
  • Indenting line 3 by two spaces changes nothing in Lua but fails the test. /^\s*o\.window/m would close that without reopening the -- case.

Neither changes what a user gets, so nothing was pushed to your branch.

On the competing PR. #9651 fixes the same issue with ^steam_app_. Re-measured on the same worker: under full matching that pattern reduces to the literal class steam_app_, and both steam_app_2622380 and steam_app_battlenet read inhibitingIdle: false under it, against true under yours. Which branch lands is the maintainer's call, but that is the measurement.

The comment on line 2 still says "Games are steam_app_<id>" without qualification, which holds for Proton and umu titles rather than universally. Same cosmetic point as last time.

Waiting on the maintainer. Reviewed by Claude Opus 5 in Claude Code, with a second opinion from Codex at xhigh reasoning. Codex's first pass reported the comment-blind test as still open, reading the already-fixed file and getting it wrong; re-run pinned to the delta it retracted that and confirmed the anchors hold. The block-comment mutant above is its own finding, and I reproduced it on the worker before repeating it here.

@kvnloo
kvnloo force-pushed the fix/9636-steam-app-idle-inhibit branch from 8cf7ed2 to 66e074a Compare September 21, 2026 09:22
@kvnloo

kvnloo commented Sep 22, 2026

Copy link
Copy Markdown
Author

Verified against current quattro (fail-then-pass on scoped shell tests). Ready for maintainer review.

Scoped: steam-idle-inhibit-test.

@omarchybot omarchybot added the bug Something isn't working label Sep 27, 2026
@omarchybot omarchybot added the verified Omarchy Triage has verified that this issue is ready for final review label Oct 1, 2026
@omarchybot

Copy link
Copy Markdown
Collaborator

Re-reviewed at 66e074a5, now rebased on current quattro. The fix still works, and this is verified on a live desktop.

What was checked. On a disposable worker running Hyprland 0.56.2, loading this branch's own tree, I mapped a window per class, fullscreened it and read inhibitingIdle from hyprctl clients -j:

class base rules (quattro) this branch
steam_app_2622380 false true
steam_app_battlenet false true
steam true true
steamwebhelper, xsteam_app_1, gamescope — false

Windowed, every class reads inhibitingIdle: false, so nothing is held awake by Steam sitting in the background. ./test/shell.d/steam-idle-inhibit-test.sh fails against the base rules and passes 3 of 3 at this head, and ./test/cli exits 0. Nothing was pushed to this branch.

Competing fix. #11981 fixes the same bug a different way and already carries ready, so this one gets verified and not ready; the choice between them is the maintainer's. The difference: #11981 also inhibits idle for gamescope and stops class-steam games floating, but to do that it scopes float to the "Steam" and "Friends List" titles, so other Steam client windows (Settings, sign-in, a localized Friends List) stop floating, which the class-wide float in #759 was there for. This PR changes nothing but the missing steam_app_* match. #12114 adds the equivalent rule but bundles unrelated network and Bluetooth changes.

Reviewed by Claude Opus 5.5 in Claude Code, with a second opinion from Codex Medium, asked which of #9667, #11981 and #12114 fixes the cause most proportionately without being told my answer. It picked this one for the fewest side effects, and called adding gamescope and changing Steam's floating a product judgement rather than something the bug requires; its independence is not guaranteed. It also noted the comment on line 2 overstates matters, since a game can carry class steam too, which is cosmetic.

Waiting on the maintainer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working verified Omarchy Triage has verified that this issue is ready for final review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Screensaver fires over fullscreen Steam games every 150s: the idle_inhibit rule can never match a game

2 participants