niri-scratchpad: stop screencasts on stash; harden acceptance spawn wait

Stashing a window now stops an active screencast of it, rather than leaving the
consumer on a frozen last frame (a stashed window is never rendered). Covers
both stash paths - Mod+M and Mod+Shift+M's hide branch - by diffing which
windows left the layout across the action, so scratchpad_show's branch logic
isn't duplicated in the caller. Dynamic-target casts are retargeted to Nothing
rather than ended; that carve-out is documented inline.

Also widen the acceptance harness spawn wait to 30s: each test launches its own
nested niri, and a cold alacritty start occasionally exceeded the old 10s.
Deliberately not a retry, which could double-spawn and corrupt window counts.

117 unit tests and 8/8 live acceptance pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
funman300
2026-07-18 11:04:14 -07:00
parent f557ffdfc7
commit 640deb397e
2 changed files with 68 additions and 7 deletions
+13 -4
View File
@@ -97,17 +97,26 @@ class Niri:
time.sleep(0.15)
return self.windows()
def spawn_window(self):
"""Spawn an alacritty window and return its id once it appears."""
def spawn_window(self, timeout=30):
"""Spawn an alacritty window and return its id once it appears.
The wait is deliberately generous: every test launches its own nested
niri, so a cold alacritty start can occasionally be slow under that
load. Do NOT convert this into a retry — re-issuing the spawn risks a
second window arriving late and corrupting the window counts the tests
assert on. A slow test beats a flaky one.
"""
before = {w["id"] for w in self.windows()}
self.action("spawn", "--", "alacritty")
t0 = time.time()
while time.time() - t0 < 10:
while time.time() - t0 < timeout:
new = [w for w in self.windows() if w["id"] not in before]
if new:
return new[0]["id"]
time.sleep(0.15)
raise RuntimeError("spawned window never appeared")
raise RuntimeError(
f"spawned window never appeared within {timeout}s "
f"(compositor alive={self.alive()})")
def by_id(self, i):
return next((w for w in self.windows() if w["id"] == i), None)