feat: propagate client screen size to web runtime

This commit is contained in:
2026-04-24 18:26:11 +00:00
parent 627910f07b
commit 8863943d79
3 changed files with 128 additions and 12 deletions
+66 -5
View File
@@ -8,11 +8,16 @@ from http.server import BaseHTTPRequestHandler, HTTPServer
DISPLAY = os.environ.get("DISPLAY", ":1")
CHROME_WINDOW_SIZE = os.environ.get("CHROME_WINDOW_SIZE", "1920,1080")
RESOLUTION_MIN_WIDTH = int(os.environ.get("WEB_RESOLUTION_MIN_WIDTH", "1024"))
RESOLUTION_MIN_HEIGHT = int(os.environ.get("WEB_RESOLUTION_MIN_HEIGHT", "720"))
RESOLUTION_MAX_WIDTH = int(os.environ.get("WEB_RESOLUTION_MAX_WIDTH", "3840"))
RESOLUTION_MAX_HEIGHT = int(os.environ.get("WEB_RESOLUTION_MAX_HEIGHT", "2160"))
_state = {
"proc": None,
"mode": "idle",
"target": "",
"resolution": CHROME_WINDOW_SIZE,
}
_lock = threading.Lock()
@@ -50,7 +55,37 @@ def _start_process(cmd: list[str], mode: str, target: str) -> None:
_state["target"] = target
def open_web(url: str) -> None:
def _sanitize_resolution(width: int | None, height: int | None) -> tuple[int, int]:
if not width or not height:
try:
default_w, default_h = [int(x) for x in CHROME_WINDOW_SIZE.split(",", 1)]
return default_w, default_h
except Exception:
return 1920, 1080
safe_w = max(RESOLUTION_MIN_WIDTH, min(int(width), RESOLUTION_MAX_WIDTH))
safe_h = max(RESOLUTION_MIN_HEIGHT, min(int(height), RESOLUTION_MAX_HEIGHT))
return safe_w, safe_h
def apply_resolution(width: int | None, height: int | None) -> tuple[int, int]:
safe_w, safe_h = _sanitize_resolution(width, height)
# Best effort: Xvfb usually exposes RandR and accepts xrandr -s.
try:
subprocess.run( # noqa: S603
["xrandr", "-display", DISPLAY, "-s", f"{safe_w}x{safe_h}"],
check=False,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
except Exception:
pass
_state["resolution"] = f"{safe_w},{safe_h}"
return safe_w, safe_h
def open_web(url: str, width: int | None = None, height: int | None = None) -> None:
safe_w, safe_h = apply_resolution(width, height)
cmd = [
"chromium",
"--no-sandbox",
@@ -65,7 +100,7 @@ def open_web(url: str) -> None:
"--ignore-certificate-errors",
"--allow-insecure-localhost",
"--allow-running-insecure-content",
f"--window-size={CHROME_WINDOW_SIZE}",
f"--window-size={safe_w},{safe_h}",
"--no-first-run",
"--no-default-browser-check",
url,
@@ -125,7 +160,16 @@ class Handler(BaseHTTPRequestHandler):
if self.path == "/health":
proc = _state.get("proc")
running = bool(proc and proc.poll() is None)
self._json(200, {"ok": True, "mode": _state.get("mode", "idle"), "running": running, "target": _state.get("target", "")})
self._json(
200,
{
"ok": True,
"mode": _state.get("mode", "idle"),
"running": running,
"target": _state.get("target", ""),
"resolution": _state.get("resolution", CHROME_WINDOW_SIZE),
},
)
return
self._json(404, {"detail": "Not found"})
@@ -137,9 +181,26 @@ class Handler(BaseHTTPRequestHandler):
if not (url.startswith("http://") or url.startswith("https://")):
self._json(400, {"detail": "Invalid URL"})
return
width = data.get("width")
height = data.get("height")
with _lock:
open_web(url)
self._json(200, {"ok": True, "mode": "web", "target": url})
open_web(url, width=width, height=height)
self._json(
200,
{
"ok": True,
"mode": "web",
"target": url,
"resolution": _state.get("resolution", CHROME_WINDOW_SIZE),
},
)
return
if self.path == "/resolution":
width = data.get("width")
height = data.get("height")
with _lock:
safe_w, safe_h = apply_resolution(width, height)
self._json(200, {"ok": True, "width": safe_w, "height": safe_h})
return
if self.path == "/rdp":
with _lock: