HydraIssues

[RESOLVED by #507 M4 in-scene overlay] Stream exit overlay must be pinned on omarchy heads (Hyprland)
closed bug Project: hydraheadflatscreen Reporter: 18 Aug 2026 11:09

Description

Follow-up found while verifying the #500 fix on cranky-toaster-86: the fork's floating exit overlay (StreamOverlay.qml, the "⋯ / Exit experience" menu) does not follow the stream window on omarchy heads, so a visitor can be left with no way to quit an experience.

Root cause: KioskBridge.makeFollowAllSpaces() is macOS-only (NSWindow collectionBehavior); on Linux it is an explicit no-op, and Hyprland ignores the X11 EWMH sticky state for Xwayland windows, so the overlay stays on whatever workspace it was born on while the stream fullscreens elsewhere.

Validated fix (live on cranky-toaster-86, verified with a real stream + screenshot): Hyprland window rules pinning the overlay. The overlay is the only floating window of class Moonlight (kiosk/stream windows tile or fullscreen), so match:float 1 selects exactly it:

windowrule = pin on, match:class Moonlight, match:float 1
windowrule = border_size 0, match:class Moonlight, match:float 1

(Syntax as used by Hyprland 0.56 / omarchy defaults; the border_size rule removes the stray Hyprland border the floating overlay otherwise gets.)

Ask: hydraheadflatscreen should provision these rules on omarchy heads — it already manages omarchy state (screensaver flags in ~/.local/state/omarchy/), and hyprland.conf sources user config; a drop-in the agent writes plus hyprctl reload at startup would cover the fleet. Currently the rules live only in this head's ~/.config/hypr/hyprland.conf.

Comments (2)

api 18 Aug 2026 11:18

Update after field testing on cranky-toaster-86: plain pinning is the wrong fix on dual-use machines — a pinned overlay sits on every workspace, including ones where the user is doing unrelated work. Replaced with an event-driven follower that keeps the overlay on the app's workspace (the true equivalent of macOS makeFollowAllSpaces joining the app's Space):

  • ~/.local/bin/hydra-overlay-follow: subscribes to Hyprland socket2 events (openwindow/movewindow/closewindow/changefloatingmode) and moves any floating moonlight-class window to the workspace of its process's main window (falling back to the fullscreen-first main). Matches class regex moonlight case-insensitively because streams run either inside the kiosk instance (class Moonlight) or as a separate process (class com.moonlight_stream.Moonlight).
  • Started via exec-once in ~/.config/hypr/autostart.conf; flock-guarded against double start.
  • Kept windowrule: windowrule = border_size 0, match:class Moonlight, match:float 1 (cosmetic only).

Verified: overlay tracks the kiosk window across workspace moves within ~1 s, lands on the stream's workspace for separate-process streams, and the user successfully quit a live stream via the overlay menu.

Two additional fork-side observations from testing (may deserve their own issues):

  1. On Linux, after a stream ends, the kiosk window sometimes fails to re-map on the agent's POST /window/show (process alive, "kiosk window shown" logged, no mapped window; a second window/show fixed it). Likely a Qt/Xwayland showFullScreen-after-hide race in LocalServer::handleWindowShow.
  2. handleWindowShow re-shows Tool windows, so a stale exit overlay from the kiosk instance stays mapped even when the kiosk window itself failed to map — the follower papers over this, but the overlay lifecycle on Linux deserves a look.

For fleet provisioning, the agent should ship the follower script + autostart entry (or equivalent logic) on omarchy heads instead of pin windowrules.

api 18 Aug 2026 11:41

Correction to my previous comment: observation 1 (kiosk window failing to re-map after stream end) was NOT a fork bug — it coincided with the kiosk_disabled rollout for this head (hydraheadflatscreen v2.2.3, commit 311c7df: workstation heads opt out of the kiosk UI). The window state I saw was the old v2.2.2 agent, the new kiosk-mode switch-off, and my manual window/show fighting each other. Retracted.

The overlay follower is compatible with kiosk-less mode: separate-process streams (class com.moonlight_stream.Moonlight) carry their own exit overlay, which the follower matches to its stream window by pid. Verified live during a stream with kiosk mode being disabled. Observation 2 (LocalServer handleWindowShow re-shows Tool windows, so a kiosk-instance overlay can outlive its hidden main window) still stands, but becomes moot on heads with kiosk_disabled.