#!/usr/bin/env python3 """Private Xvfb/AT-SPI proof for GTK alert message capture.""" import os from pathlib import Path import subprocess import sys import tempfile import time sys.dont_write_bytecode = True def inside(): fixture = subprocess.Popen([sys.executable, str(Path(__file__).with_name("gtk_alert.py"))]) try: deadline = time.monotonic() + 10 window = "" while time.monotonic() < deadline: result = subprocess.run( ["xdotool", "search", "--onlyvisible", "--name", "^Cthulhu Alert Probe$"], capture_output=True, text=True, ) if result.returncode == 0: window = result.stdout.splitlines()[0] break time.sleep(0.02) if not window: raise RuntimeError("GTK alert probe window missing") environment = dict(os.environ, CTHULHU_ALERT_WINDOW=window) environment.setdefault("GOCACHE", "/tmp/cthulhu-cache") subprocess.run( ["go", "test", "./internal/atspi", "-run", "^TestNativeGTKAlertMessage$", "-count=1", "-timeout=20s"], cwd=Path(__file__).resolve().parents[1], env=environment, check=True, timeout=25, ) environment["CTHULHU_NATIVE_YAD"] = "1" for name in ("TestNativeYADQuestionMessage", "TestNativeYADListMessage", "TestNativeYADPowerListMessage"): subprocess.run( ["go", "test", "./internal/atspi", "-run", f"^{name}$", "-count=1", "-timeout=20s"], cwd=Path(__file__).resolve().parents[1], env=environment, check=True, timeout=25, ) # Keep the radio fixture in the same private X11/AT-SPI session. environment["CTHULHU_NATIVE_RADIO"] = "1" subprocess.run( ["go", "test", "./internal/atspi", "-run", "^TestNativeGTKRadioGroupName$", "-count=1", "-timeout=20s"], cwd=Path(__file__).resolve().parents[1], env=environment, check=True, timeout=25, ) finally: fixture.terminate() fixture.wait(timeout=3) def main(): if len(sys.argv) == 2 and sys.argv[1] == "--inside": inside() return with tempfile.TemporaryDirectory(prefix="cthulhu-alert-"): read_fd, write_fd = os.pipe() server = subprocess.Popen( ["Xvfb", "-displayfd", str(write_fd), "-screen", "0", "800x600x24", "-nolisten", "tcp"], pass_fds=(write_fd,), stderr=subprocess.DEVNULL, ) os.close(write_fd) try: with os.fdopen(read_fd) as reader: display = reader.readline().strip() if not display: raise RuntimeError("Xvfb failed to start") environment = dict(os.environ, DISPLAY=":" + display, XDG_SESSION_TYPE="x11") environment.pop("DBUS_SESSION_BUS_ADDRESS", None) environment.pop("AT_SPI_BUS_ADDRESS", None) environment.pop("WAYLAND_DISPLAY", None) subprocess.run( ["dbus-run-session", "--", sys.executable, str(Path(__file__).resolve()), "--inside"], env=environment, check=True, timeout=50, ) finally: server.terminate() server.wait(timeout=3) if __name__ == "__main__": main()