2 Commits
Author SHA1 Message Date
MichaelScottsmanandClaude Opus 5.5 7d7f55a5b4 Installer puts the release's shipped glassd in place; README on native glass out of the box
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 16:28:05 -04:00
MichaelScottsmanandClaude Opus 5.5 d9d73383c2 Ship glassd and native mode on by default: install works out of the box
- native/glassd/prebuilt/glassd: the Frame's glassd built from these sources, shipped by sync.
- glass.py install: the shipped binary in place first, then a build from source over it (kept on a failed
  build), then a check that glassd is ready.
- lgs_shell start: puts the shipped binary in place when glassd is missing, so the Liquid Glass toggle run
  during an install never starts CSS-only (what left the glass transparent).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 16:27:55 -04:00
5 changed files with 59 additions and 5 deletions

No files matched your search

+3 -1
View File
@@ -58,7 +58,7 @@ The [uninstall](#uninstall) command (or `python glass.py uninstall`) removes all
## From the PC
```bash
python glass.py install # copy this checkout to the headset and add the launcher (for development)
python glass.py install # copy this checkout to the headset, set up glassd and add the launcher (for development)
python glass.py on | off | toggle | status
python glass.py dial 0.7 # glass intensity: 0 = clearest, 1 = most opaque (saved with your glass settings)
python glass.py uninstall
@@ -66,6 +66,8 @@ python glass.py uninstall
On the headset itself, `~/.local/share/glass-shell/device/lgs on|off|toggle|status|dial V` does the same.
Native glass works out of the box. Releases ship glassd built for the Frame (`native/glassd/prebuilt/glassd`), and the installer puts it in place. `python glass.py install` does the same, then rebuilds glassd from the checkout's sources over it (if that build fails, the shipped binary stays). The daemon also puts the shipped binary in place whenever glassd is missing, so the LiquidAss toggle never starts CSS-only. Native mode is on by default (`device/defaults.json`).
## How it works
| Piece | Role |
+26
View File
@@ -77,6 +77,7 @@ import collections # noqa: E402
import hashlib # noqa: E402
import json # noqa: E402
import os # noqa: E402
import shutil # noqa: E402
import signal # noqa: E402
import subprocess # noqa: E402
import time # noqa: E402
@@ -3362,6 +3363,29 @@ def core_args(argv):
return out
GLASSD_PREBUILT = os.path.join(lgs.ROOT, "native", "glassd", "prebuilt", "glassd")
def ensure_glassd(path=GLASSD_BIN):
"""The shipped glassd (native/glassd/prebuilt/glassd) in place when no build is there yet, so native
glass works out of the box and a Liquid Glass toggle that runs before a build finishes is never stuck
CSS-only. True when an executable glassd is in place."""
if os.access(path, os.X_OK):
return True
if path != GLASSD_BIN or not os.access(GLASSD_PREBUILT, os.R_OK):
return False
try:
tmp = path + ".tmp"
shutil.copyfile(GLASSD_PREBUILT, tmp)
os.chmod(tmp, 0o755)
os.replace(tmp, path)
log("glassd: no build here; the shipped binary is in place")
return True
except OSError as e:
log(f"glassd: could not put the shipped binary in place: {e}")
return False
def start(glassd=GLASSD_BIN, stay=False, glassd_args=None, native=None, test_report=None, assume_caps=None):
"""Start the unit. Also resumes SteamVR page theming that a lab "--theme
off" on a vr: page paused.
@@ -3379,6 +3403,8 @@ def start(glassd=GLASSD_BIN, stay=False, glassd_args=None, native=None, test_rep
loser's systemd-run fail with "already loaded" although a unit ran (review
R1 m5); if the lock cannot be had in 60 s, it goes on and treats that
error as running."""
if glassd and glassd != "none":
ensure_glassd(glassd)
try:
lk = FileLock(START_LOCK, 60).__enter__()
except (OSError, TimeoutError):
+25 -4
View File
@@ -161,12 +161,13 @@ def sync(client, only=None):
for f in sorted(p.rglob("*")):
if f.is_dir() or "__pycache__" in f.parts or f.suffix == ".pyc":
continue
# native/: sources only; builds happen on the Frame
if sub == "native" and ("build" in f.parts or f.suffix in (".o", ".so", ".png", ".jpg")
or (f.suffix == "" and f.name not in ("Makefile",))):
# native/: sources only (builds happen on the Frame), plus the shipped glassd binary
prebuilt = sub == "native" and "prebuilt" in f.parts
if sub == "native" and not prebuilt and ("build" in f.parts or f.suffix in (".o", ".so", ".png", ".jpg")
or (f.suffix == "" and f.name not in ("Makefile",))):
continue
ti = tar.gettarinfo(str(f), arcname=str(f.relative_to(ROOT)).replace("\\", "/"))
ti.mode = 0o755 if f.suffix in (".py", ".sh") or f.name == "lgs" else 0o644
ti.mode = 0o755 if f.suffix in (".py", ".sh") or f.name == "lgs" or prebuilt else 0o644
ti.uid = ti.gid = 1000
ti.uname = ti.gname = "steamos"
with open(f, "rb") as fh:
@@ -207,6 +208,21 @@ def native_build(client, fake=False):
return code
def install_glassd(client):
"""glassd for native mode: the shipped binary (native/glassd/prebuilt/glassd), then a build from
the synced sources over it. Exit code 0 when a working glassd is in place."""
d = f"{REMOTE}/native/glassd"
code, _, _ = sh(client, f"test -x {d}/prebuilt/glassd && install -m755 {d}/prebuilt/glassd {d}/glassd "
f"&& echo 'glassd: shipped binary in place'", timeout=60)
if native_build(client):
print("glassd: the build from source failed; the shipped binary stays")
code, _, _ = sh(client, f"{d}/glassd --help >/dev/null 2>&1; test -x {d}/glassd && echo 'glassd: ready ({d}/glassd)'",
timeout=60)
if code:
print("glassd: no working binary; native glass is off until `python glass.py native-build` succeeds")
return code
def lgs(client, *args):
q = " ".join(shlex.quote(a) for a in args)
code, _, _ = sh(client, f"{PY} {REMOTE}/device/lgs.py {q}", timeout=120)
@@ -1136,6 +1152,11 @@ def main(argv):
sync(c, only=rest or None)
elif cmd == "install":
sync(c)
# native glass out of the box: the shipped glassd goes in place first (the Liquid Glass toggle
# may run at once), then a build from these sources replaces it; a failed build keeps it
code = install_glassd(c)
if code:
return code
sh(c, f"install -Dm644 {REMOTE}/device/glass-shell.desktop {DESKTOP} && "
f"chmod 755 {REMOTE}/device/lgs {REMOTE}/device/lgs.py && "
f"(update-desktop-database ~/.local/share/applications >/dev/null 2>&1 || true) && "
+5
View File
@@ -74,6 +74,11 @@ install_app() {
mkdir -p "$tmp/new/native/glassd"
cp -p "$DEST/native/glassd/glassd" "$tmp/new/native/glassd/glassd"
fi
# Native glass out of the box: the release's shipped glassd (built for the Frame) when none was kept
if [ ! -e "$tmp/new/native/glassd/glassd" ] && [ -f "$tmp/new/native/glassd/prebuilt/glassd" ]; then
cp "$tmp/new/native/glassd/prebuilt/glassd" "$tmp/new/native/glassd/glassd"
chmod 755 "$tmp/new/native/glassd/glassd"
fi
rm -rf "$DEST.old"
[ -d "$DEST" ] && mv "$DEST" "$DEST.old"
mv "$tmp/new" "$DEST"
Binary file not shown.