fix: hold the DVD cover until the disc menu is actually showing

The readiness condition was playback state alone, and on a real disc
VLC reports playing well before its window has taken the screen. The
cover came off onto VLC's ordinary tiled startup window — black, sized
to everything except the dock's reserved strip — and the disc menu only
arrived afterwards. Exactly the state the cover exists to hide.

Ask sway instead. VLC only takes the display when its window goes
fullscreen, and the tree says when that happens. The cover now comes off
when VLC reports playing or paused, its window is fullscreen, and 800ms
have passed for the menu to draw its first frames. The playback check
runs first because it is local and cheap; the tree is only walked once
VLC claims to be playing something.

The twenty second deadline is unchanged: a cover with nothing behind it
is still the one outcome DVD mode must never produce.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
ekklesia
2026-09-04 23:17:37 -05:00
co-authored by Claude Opus 5
parent 719b856040
commit 37f8166401
3 changed files with 157 additions and 24 deletions
+95
View File
@@ -106,6 +106,101 @@ print("6. the disc is the last argument")
check("dvd:// selects dvdnav for menus", command[-1] == "dvd:///dev/sr0")
print()
print("7. the loading surface waits for a fullscreen VLC window")
import json # noqa: E402
import os # noqa: E402
import subprocess # noqa: E402
import tempfile # noqa: E402
def tree_with(app, fullscreen):
return {
"tree": {
"type": "root", "id": 1, "nodes": [{
"type": "output", "id": 2, "name": "HDMI-A-1", "nodes": [{
"type": "workspace", "id": 3, "name": "1",
"nodes": ([] if app is None else [{
"type": "con", "id": 10, "pid": 100,
"app_id": None,
"window_properties": {"class": app, "instance": app},
"focused": True,
"fullscreen_mode": 1 if fullscreen else 0,
"nodes": [], "floating_nodes": [],
}]),
"floating_nodes": [],
}], "floating_nodes": [],
}], "floating_nodes": [],
},
"workspaces": [{"name": "1", "focused": True, "visible": True}],
}
work = tempfile.mkdtemp()
os.makedirs(f"{work}/bin", exist_ok=True)
with open(f"{work}/bin/swaymsg", "w") as shim:
shim.write(
"#!/usr/bin/env python3\n"
"import json, os, sys\n"
"state = json.load(open(os.environ['MOCK_TREE']))\n"
"print(json.dumps(state['tree' if sys.argv[2] == 'get_tree'"
" else 'workspaces']))\n"
)
os.chmod(f"{work}/bin/swaymsg", 0o755)
os.environ["PATH"] = f"{work}/bin:" + os.environ["PATH"]
os.environ["MOCK_TREE"] = f"{work}/tree.json"
def set_tree(app, fullscreen):
with open(f"{work}/tree.json", "w") as handle:
json.dump(tree_with(app, fullscreen), handle)
ready = None
try:
import importlib.util
from importlib.machinery import SourceFileLoader
import gi
gi.require_version("Gtk", "3.0")
gi.require_version("GtkLayerShell", "0.1")
loader = SourceFileLoader("dvdsession", sys.argv[1] + "/scripts/classroom-dvd-session")
spec = importlib.util.spec_from_loader("dvdsession", loader)
module = importlib.util.module_from_spec(spec)
sys.modules["dvdsession"] = module
loader.exec_module(module)
ready = module.DvdSession.player_is_fullscreen
except Exception as error: # noqa: BLE001
print(f" skip GTK unavailable here ({type(error).__name__})")
if ready is not None:
set_tree("vlc", False)
check("a tiled VLC window is not ready", ready(None) is False)
set_tree("vlc", True)
check("a fullscreen VLC window is ready", ready(None) is True)
set_tree("Google-chrome", True)
check("someone else's fullscreen window is not VLC", ready(None) is False)
set_tree(None, False)
check("no windows at all is not ready", ready(None) is False)
check("playback state alone is no longer the condition",
"player_is_fullscreen" in module.DvdSession.watch_startup.__doc__
or "fullscreen" in module.DvdSession.watch_startup.__doc__)
check("the handover is held briefly after both agree",
500 <= module.STABILISE_MS <= 1000, f"got {module.STABILISE_MS}")
check("the safety deadline is still there",
module.LOADING_DEADLINE_SECONDS == 20)
subprocess.run(["rm", "-rf", work])
print()
print(f"passed: {passed} failed: {failed}")
sys.exit(1 if failed else 0)