Focus ring fixes for Steam - #2301
Conversation
Dumps the global and per-server focus state, including where the X server actually has keyboard focus versus the window gamescope wanted it on, and the focused app and window properties Steam reads back. Only the current connector's focus gets published to Steam, so a correct focus that never made it into the properties is invisible in a dump of the properties alone. Print each connector's focus next to the current key.
b471a05 keeps track of a focused subwindow so no-op focus rerolls don't yank keyboard focus away from it, but the XSetInputFocus call still targeted the toplevel. When the apply path re-fires after Steam's CEF has focused its browser subwindow, focus moves back to the toplevel and Steam loses its focus ring until something refocuses it. Target the preserved window instead, and let subwindow focus revert to its parent so a destroyed subwindow can't strand focus on None.
A client can drop keyboard focus to None, and with RevertToNone any revert also lands there. The FocusOut handler only corrected focus when it moved to another tracked window, and its guard never matched while focus was preserved on a subwindow. Match the stored window directly, track focus moves within the same toplevel, and take focus back when it went to None.
XGetWindowProperty hands back an allocation even when the property holds zero elements, so get_prop returned uninitialized memory for them instead of the default. The focused app and window atoms are published with zero elements whenever there is no focus.
determine_and_apply_focus publishes the focused app from the input focus window, but a global focus can hold a focus window while the input focus window is null. The dereference crashes steamcompmgr. Only read the appID when an input focus window exists. The focused app then stays zero and the atom is published with no elements.
The keyboard and mouse focus connectors normally follow SteamVR's overlay input focus grants, but SteamVR can park input focus on nothing while a launching app's overlay flickers through hide and show, and nothing regrants it until a pointer interaction. The stale connectors keep steamcompmgr publishing the previous app's focused app atoms, skip the wlserver input focus handoff, and starve mangoapp of nudges, so MangoHud sits frozen until the first click. Take keyboard and mouse focus when our connector becomes visible instead of waiting for the grant. Defer when the grant currently points at the holding connector's own overlay, so becoming visible cannot steal focus SteamVR deliberately gave another connector. Steam's per-app controller activation still follows SteamVR's own grant, so this does not cure the dead first launch, it keeps gamescope's focus state correct through it.
09ef67e to
3eacdf1
Compare
|
added some additional fixes found while working with the openvr backend, so we'll want to cherry-pick this to the steamframe branch as well. main fix for openvr is the mangohud overlay now properly drawing on a game after first launch, where previously it wouldn't until first interacting with the game. |
|
The new One problem that this patchset doesn't address is the focus ring disappearing after opening then closing the Power menu (on a Steam Deck: Steam button to bring the Steam menu up, Power menu entry, then B to dismiss the power menu and B again to dismiss the Steam menu). |
|
Hmm, I'll take a look, I don't think I tried that specific scenario. Will poke at it and see if it's a gamescope bug or steam bug. |
leaning towards a steam bug here, there's no difference between the broken and healthy state, and the ring appears after the first time you move the joystick or dpad. |
|
@oSoMoN the bug you noticed reproduces in plain big picture mode without gamescope involved, so I'm inclined to merge this if that was the only concern |
At startup, the breathing focus ring on the Steam home screen sometimes doesn't appear, and keyboard input goes nowhere. Flipping to a dialog and back fixes it. Whether it happens depends on startup timing, which made it unbisectable.
After adding a focus_info debug command, it showed that Steam's CEF takes input on a subwindow inside the toplevel, and focuses it with XSetInputFocus(RevertToParent). Since b471a05, gamescope tracks that subwindow so no-op focus rerolls don't yank focus away from it, but the XSetInputFocus call itself still targeted the toplevel. When the focus apply path re-fires during startup churn after CEF has focused its subwindow, focus moves back to the toplevel. CEF sees FocusOut on its browser window, considers the context unfocused, and stops drawing the ring. Gamescope's bookkeeping already records the subwindow as focused, so it never re-applies, and the state sticks until something forces a new focus change.
Broken state info dump:
Working state with focus ring dump:
To repro the original bug, the easiest way to do so is just continuously run a loop of
gamescope -e --xwayland-count 2 -- steam -steamdeck -steamos3 -steampal -gamepaduiand then if the focus ring appears after Steam loads, kill gamescope and run the command again. Usually within 5-10 tries you can hit this bug, but I've had it take up to 15 tries before. This series has survived 75 restarts here so far with nested gamescope, I'll verify on DRM backend tomorrow.