mirror of
https://github.com/DeeJanuz/frametop.git
synced 2026-10-06 02:00:06 +02:00
SteamVR's tools find SteamVR from a terminal in the Frametop desktop
The desktop has its own XDG_CONFIG_HOME (~/.config/frametop), and SteamVR's tools and OpenVR read their path registry from there. So from a terminal in the desktop: - pointer/driver/install.sh (install.sh step 4, every reinstall or update from Konsole) wrote a new registry, ~/.config/frametop/openvr/openvrpaths.vrpath, with only our driver and "runtime": null, and never registered the driver with SteamVR. That stray file then hid SteamVR from every OpenVR program started in the desktop. - scripts/update-check.py (and so doctor.sh and report.sh) reported OpenVR "can't connect to SteamVR as a background app" (VRInitError_Init_PathRegistryNotFound, or InstallationNotFound with the stray file) and "vrcmd --overlays lists no overlays". A user's report of 2026-10-05 showed both, with SteamVR and Frametop's services fine. - ft-layout's vrcmd calls (the gamescope backend) found no overlays. They now run with XDG_CONFIG_HOME=~/.config: the driver installer (install, uninstall, probe, aimhere), update-check.py (for all its checks: nothing there reads the desktop's own config), report.sh's vrpathreg show, and ft-layout's vrcmd. report.sh doesn't set it for the whole report, since session/fix-panels.py --check reads the desktop's Plasma config through it. The driver installer also removes the stray registry (only vrpathreg's, with no runtime), and update-check.py warns about one. And vrpathreg runs `xdg-open vrmonitor://driverinstalled` to tell SteamVR's desktop monitor, which the Frame doesn't have: in the desktop that showed "could not read file vrmonitor://driverinstalled" on every install. A stand-in xdg-open on its PATH takes it, so install.sh no longer filters the step's output. Tested in a fake HOME with a copy of SteamVR's registry, a stray one, and the desktop's XDG_CONFIG_HOME: the new installer removes the stray file, registers the driver in the copy, and never reaches xdg-open; the old one wrote the stray file, left the copy alone, and ran xdg-open. update-check.py from that environment: OpenVR and vrcmd ok (the old one fails both); its stray-registry warning fires on a seeded file. ft-layout's vrcmd: 119 overlays (was 0). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d39fbb9146
commit
307e2b7308
6 files changed
+40
-9
No files matched your search
+1
-1
@@ -169,7 +169,7 @@ The Frame controllers can be mapped like mouse buttons, but they aren't input de
|
|||||||
|
|
||||||
## The desktop session
|
## The desktop session
|
||||||
|
|
||||||
The session is modeled on SteamOS's `steamos-nested-desktop` and runs beside it. It has its own runtime directory, config (`~/.config/frametop`), and state, so it never disturbs the stock desktop's layout or panels. It runs on a private D-Bus from `dbus-run-session`, which has two consequences. KDE only launches apps in systemd scopes when systemd is on the session bus, so everything started in the desktop lands in its systemd unit, and stopping the unit would kill all of it; `session/keep-apps.sh` moves those programs out first. And tools that need the real user bus, like podman and `distrobox-host-exec`, have to be pointed at it explicitly.
|
The session is modeled on SteamOS's `steamos-nested-desktop` and runs beside it. It has its own runtime directory, config (`~/.config/frametop`), and state, so it never disturbs the stock desktop's layout or panels. It runs on a private D-Bus from `dbus-run-session`, which has two consequences. KDE only launches apps in systemd scopes when systemd is on the session bus, so everything started in the desktop lands in its systemd unit, and stopping the unit would kill all of it; `session/keep-apps.sh` moves those programs out first. And tools that need the real user bus, like podman and `distrobox-host-exec`, have to be pointed at it explicitly. Its own config folder also hides SteamVR's path registry (`~/.config/openvr/openvrpaths.vrpath`) from everything started in it: OpenVR programs there fail with `VRInitError_Init_PathRegistryNotFound`, and `vrpathreg adddriver` writes a new registry under `~/.config/frametop/openvr` that has no SteamVR in it and that SteamVR never reads. So Frametop's scripts run SteamVR's tools with `XDG_CONFIG_HOME=~/.config`.
|
||||||
|
|
||||||
The VR launcher starts the session from the Steam client, and the client's environment came along: `LD_LIBRARY_PATH` pointing at Steam's own runtime, whose `libavcodec` has no H.264 decoder, so VLC in the desktop couldn't play most videos, plus the client's overlay and launch settings. The session script drops the client's variables before it starts anything. SteamOS's global Mesa settings (`/usr/share/deckard/mesavars.sh`) stay, and the gamescope session's Vulkan layer (`ENABLE_GAMESCOPE_WSI`) is only kept for the gamescope backend.
|
The VR launcher starts the session from the Steam client, and the client's environment came along: `LD_LIBRARY_PATH` pointing at Steam's own runtime, whose `libavcodec` has no H.264 decoder, so VLC in the desktop couldn't play most videos, plus the client's overlay and launch settings. The session script drops the client's variables before it starts anything. SteamOS's global Mesa settings (`/usr/share/deckard/mesavars.sh`) stay, and the gamescope session's Vulkan layer (`ENABLE_GAMESCOPE_WSI`) is only kept for the gamescope backend.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -75,7 +75,7 @@ step "3/10 input relay (keeps Bluetooth mice working in SteamVR, device roles, b
|
|||||||
|
|
||||||
step "4/10 3D mouse: SteamVR driver"
|
step "4/10 3D mouse: SteamVR driver"
|
||||||
"$root/pointer/driver/build.sh"
|
"$root/pointer/driver/build.sh"
|
||||||
"$root/pointer/driver/install.sh" install 2>&1 | grep -v xdg-open
|
"$root/pointer/driver/install.sh" install
|
||||||
|
|
||||||
step "5/10 3D mouse: pointer helper service"
|
step "5/10 3D mouse: pointer helper service"
|
||||||
"$root/pointer/helper/build.sh"
|
"$root/pointer/helper/build.sh"
|
||||||
|
|||||||
+2
-1
@@ -534,7 +534,8 @@ def capture_screens():
|
|||||||
# ---------------------------------------------------------------- gamescope (dashboard panels)
|
# ---------------------------------------------------------------- gamescope (dashboard panels)
|
||||||
|
|
||||||
def vrcmd(*args, timeout=10):
|
def vrcmd(*args, timeout=10):
|
||||||
env = dict(os.environ, LD_LIBRARY_PATH=os.path.dirname(VRCMD))
|
# SteamVR's config folder: in the desktop, XDG_CONFIG_HOME is its own (docs/design.md).
|
||||||
|
env = dict(os.environ, LD_LIBRARY_PATH=os.path.dirname(VRCMD), XDG_CONFIG_HOME=os.path.expanduser("~/.config"))
|
||||||
try:
|
try:
|
||||||
return subprocess.run([VRCMD, *args], capture_output=True, text=True, timeout=timeout, env=env).stdout
|
return subprocess.run([VRCMD, *args], capture_output=True, text=True, timeout=timeout, env=env).stdout
|
||||||
except (OSError, subprocess.TimeoutExpired):
|
except (OSError, subprocess.TimeoutExpired):
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ frame="$root/scripts/frame.sh"
|
|||||||
src=$FRAME_REPO/pointer/driver
|
src=$FRAME_REPO/pointer/driver
|
||||||
dest='$HOME/.local/share/frametop/ft_pointer' # expanded on the Frame, in the commands below
|
dest='$HOME/.local/share/frametop/ft_pointer' # expanded on the Frame, in the commands below
|
||||||
reg='/opt/steamvr/bin/linuxarm64/vrpathreg'
|
reg='/opt/steamvr/bin/linuxarm64/vrpathreg'
|
||||||
|
# SteamVR's tools with SteamVR's config folder and libraries. A terminal in the Frametop desktop
|
||||||
|
# has XDG_CONFIG_HOME=~/.config/frametop (session/frametop-session.sh), where vrpathreg finds no
|
||||||
|
# registry, so it made one there that SteamVR never reads.
|
||||||
|
steamvr='env XDG_CONFIG_HOME=$HOME/.config LD_LIBRARY_PATH=/opt/steamvr/bin/linuxarm64' # expanded on the Frame
|
||||||
|
|
||||||
case ${1:-install} in
|
case ${1:-install} in
|
||||||
install)
|
install)
|
||||||
@@ -21,6 +25,11 @@ case ${1:-install} in
|
|||||||
# Replacing the files of a driver SteamVR has loaded leaves its input bindings in a bad
|
# Replacing the files of a driver SteamVR has loaded leaves its input bindings in a bad
|
||||||
# state (the 3D mouse no longer gets the laser) until SteamVR restarts, so an unchanged
|
# state (the 3D mouse no longer gets the laser) until SteamVR restarts, so an unchanged
|
||||||
# driver is left alone.
|
# driver is left alone.
|
||||||
|
# A registry an earlier install made in the desktop's config folder (see steamvr above) has
|
||||||
|
# no SteamVR in it, and hid SteamVR from OpenVR programs started in the desktop
|
||||||
|
# (VRInitError_Init_InstallationNotFound): it goes.
|
||||||
|
# vrpathreg runs 'xdg-open vrmonitor://driverinstalled' for SteamVR's desktop monitor, which
|
||||||
|
# the Frame doesn't have, so the desktop said "could not read file": a stand-in takes it.
|
||||||
"$frame" --host "set -e; test -f $src/build/driver_ft_pointer.so
|
"$frame" --host "set -e; test -f $src/build/driver_ft_pointer.so
|
||||||
rm -rf $dest.new; mkdir -p $dest.new/bin/linuxarm64
|
rm -rf $dest.new; mkdir -p $dest.new/bin/linuxarm64
|
||||||
cp -r $src/ft_pointer/. $dest.new/
|
cp -r $src/ft_pointer/. $dest.new/
|
||||||
@@ -31,15 +40,22 @@ else
|
|||||||
rm -rf $dest; mv $dest.new $dest
|
rm -rf $dest; mv $dest.new $dest
|
||||||
echo 'installed; restart SteamVR to load it'
|
echo 'installed; restart SteamVR to load it'
|
||||||
fi
|
fi
|
||||||
LD_LIBRARY_PATH=/opt/steamvr/bin/linuxarm64 $reg adddriver $dest
|
stray=\$HOME/.config/frametop/openvr/openvrpaths.vrpath
|
||||||
LD_LIBRARY_PATH=/opt/steamvr/bin/linuxarm64 $reg show | grep -A3 -i 'external'" ;;
|
if grep -qs '\"jsonid\" : \"vrpathreg\"' \$stray && grep -qsE '\"runtime\"[[:space:]]*:[[:space:]]*null' \$stray; then
|
||||||
|
rm -f \$stray; rmdir \$HOME/.config/frametop/openvr 2>/dev/null || true
|
||||||
|
echo 'removed a SteamVR path registry an earlier install left in ~/.config/frametop/openvr'
|
||||||
|
fi
|
||||||
|
noopen=\$(mktemp -d); trap 'rm -rf \$noopen' EXIT
|
||||||
|
printf '#!/bin/sh\nexit 0\n' > \$noopen/xdg-open; chmod +x \$noopen/xdg-open
|
||||||
|
PATH=\$noopen:\$PATH $steamvr $reg adddriver $dest
|
||||||
|
$steamvr $reg show | grep -A3 -i 'external'" ;;
|
||||||
uninstall)
|
uninstall)
|
||||||
"$frame" --host "LD_LIBRARY_PATH=/opt/steamvr/bin/linuxarm64 $reg removedriver $dest; rm -rf $dest; echo 'removed; restart SteamVR to unload it'" ;;
|
"$frame" --host "$steamvr $reg removedriver $dest; rm -rf $dest; echo 'removed; restart SteamVR to unload it'" ;;
|
||||||
send)
|
send)
|
||||||
"$frame" --host "python3 -c 'import socket,sys; s=socket.socket(socket.AF_UNIX,socket.SOCK_DGRAM); s.sendto(sys.argv[1].encode(), \"\\0ft_pointer\")' $(printf %q "${2:?command}")" ;;
|
"$frame" --host "python3 -c 'import socket,sys; s=socket.socket(socket.AF_UNIX,socket.SOCK_DGRAM); s.sendto(sys.argv[1].encode(), \"\\0ft_pointer\")' $(printf %q "${2:?command}")" ;;
|
||||||
probe) "$frame" -C pointer/probe 'LD_LIBRARY_PATH=/opt/steamvr/bin/linuxarm64 ./build/vrprobe' ;;
|
probe) "$frame" -C pointer/probe "$steamvr ./build/vrprobe" ;;
|
||||||
aimhere)
|
aimhere)
|
||||||
read -r yaw pitch < <("$frame" -C pointer/probe 'LD_LIBRARY_PATH=/opt/steamvr/bin/linuxarm64 ./build/vrprobe' | sed -n 's/^head yaw = \([-0-9.]*\) pitch = \([-0-9.]*\)$/\1 \2/p')
|
read -r yaw pitch < <("$frame" -C pointer/probe "$steamvr ./build/vrprobe" | sed -n 's/^head yaw = \([-0-9.]*\) pitch = \([-0-9.]*\)$/\1 \2/p')
|
||||||
[ -n "${yaw:-}" ] || { echo "head pose not valid (headset off?)" >&2; exit 1; }
|
[ -n "${yaw:-}" ] || { echo "head pose not valid (headset off?)" >&2; exit 1; }
|
||||||
"$0" send "aim $yaw $pitch" && echo "aimed at yaw $yaw pitch $pitch" ;;
|
"$0" send "aim $yaw $pitch" && echo "aimed at yaw $yaw pitch $pitch" ;;
|
||||||
log) "$frame" --host "grep -iE 'ft_pointer' ~/.local/share/Steam/logs/vrserver.txt | tail -n ${2:-20}" ;;
|
log) "$frame" --host "grep -iE 'ft_pointer' ~/.local/share/Steam/logs/vrserver.txt | tail -n ${2:-20}" ;;
|
||||||
|
|||||||
+2
-1
@@ -26,7 +26,8 @@ for u in frametop-input-relay frametop-pointer frametop-power; do
|
|||||||
done
|
done
|
||||||
echo "desktop: $(pgrep -x ft-screens >/dev/null && echo running || echo 'not running'), plasmashell: $(pgrep -c plasmashell || true)"
|
echo "desktop: $(pgrep -x ft-screens >/dev/null && echo running || echo 'not running'), plasmashell: $(pgrep -c plasmashell || true)"
|
||||||
echo "paused for VR games: $(cat /run/user/$(id -u)/frametop-pause.json 2>/dev/null || echo 'no (never paused since boot)')"
|
echo "paused for VR games: $(cat /run/user/$(id -u)/frametop-pause.json 2>/dev/null || echo 'no (never paused since boot)')"
|
||||||
LD_LIBRARY_PATH=/opt/steamvr/bin/linuxarm64 /opt/steamvr/bin/linuxarm64/vrpathreg show 2>/dev/null | sed -n '/xternal/,$p'
|
# SteamVR's config folder: a terminal in the desktop has the session's own (docs/design.md).
|
||||||
|
XDG_CONFIG_HOME=$HOME/.config LD_LIBRARY_PATH=/opt/steamvr/bin/linuxarm64 /opt/steamvr/bin/linuxarm64/vrpathreg show 2>/dev/null | sed -n '/xternal/,$p'
|
||||||
|
|
||||||
section "What Frametop needs from SteamOS (scripts/update-check.py)"
|
section "What Frametop needs from SteamOS (scripts/update-check.py)"
|
||||||
python3 "$repo/scripts/update-check.py" 2>&1 || true
|
python3 "$repo/scripts/update-check.py" 2>&1 || true
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ KNOWN_GOOD = os.path.join(HOME, ".local/state/frametop/known-good.json")
|
|||||||
STEAMVR_BIN = "/opt/steamvr/bin/linuxarm64"
|
STEAMVR_BIN = "/opt/steamvr/bin/linuxarm64"
|
||||||
LAUNCHER = os.path.join(HOME, ".local/share/applications/deckard-nested-desktop.desktop")
|
LAUNCHER = os.path.join(HOME, ".local/share/applications/deckard-nested-desktop.desktop")
|
||||||
VRPATHS = os.path.join(HOME, ".config/openvr/openvrpaths.vrpath")
|
VRPATHS = os.path.join(HOME, ".config/openvr/openvrpaths.vrpath")
|
||||||
|
# The Frametop desktop has its own XDG_CONFIG_HOME (session/frametop-session.sh). An install from a
|
||||||
|
# terminal there, before pointer/driver/install.sh set SteamVR's, left vrpathreg's registry here.
|
||||||
|
STRAY_VRPATHS = os.path.join(HOME, ".config/frametop/openvr/openvrpaths.vrpath")
|
||||||
BACKLIGHT = "/sys/class/backlight/ae94000.dsi.0/brightness" # as in power/ft-powerd.cpp
|
BACKLIGHT = "/sys/class/backlight/ae94000.dsi.0/brightness" # as in power/ft-powerd.cpp
|
||||||
EYE_MMAP = "/dev/shm/eye-server.mmap"
|
EYE_MMAP = "/dev/shm/eye-server.mmap"
|
||||||
VRSERVER = "http://127.0.0.1:27062" # its web socket: input/vrws.py
|
VRSERVER = "http://127.0.0.1:27062" # its web socket: input/vrws.py
|
||||||
@@ -227,6 +230,14 @@ def check_host():
|
|||||||
else:
|
else:
|
||||||
report("FAIL", "pointer driver", "not registered with SteamVR; run pointer/driver/install.sh install, "
|
report("FAIL", "pointer driver", "not registered with SteamVR; run pointer/driver/install.sh install, "
|
||||||
"then restart SteamVR")
|
"then restart SteamVR")
|
||||||
|
try:
|
||||||
|
with open(STRAY_VRPATHS) as f:
|
||||||
|
stray = json.load(f).get("runtime") is None
|
||||||
|
except (OSError, ValueError, AttributeError):
|
||||||
|
stray = False
|
||||||
|
if stray:
|
||||||
|
report("warn", "OpenVR path registry", f"{STRAY_VRPATHS} has no SteamVR in it, and hides SteamVR from "
|
||||||
|
"OpenVR programs started in the Frametop desktop; pointer/driver/install.sh install removes it")
|
||||||
|
|
||||||
session = launcher_session()
|
session = launcher_session()
|
||||||
if session is None:
|
if session is None:
|
||||||
@@ -474,6 +485,8 @@ def main():
|
|||||||
# A terminal in the desktop has its session's runtime dir and bus; systemctl needs the real ones.
|
# A terminal in the desktop has its session's runtime dir and bus; systemctl needs the real ones.
|
||||||
os.environ["XDG_RUNTIME_DIR"] = f"/run/user/{UID}"
|
os.environ["XDG_RUNTIME_DIR"] = f"/run/user/{UID}"
|
||||||
os.environ["DBUS_SESSION_BUS_ADDRESS"] = f"unix:path=/run/user/{UID}/bus"
|
os.environ["DBUS_SESSION_BUS_ADDRESS"] = f"unix:path=/run/user/{UID}/bus"
|
||||||
|
# And its own config folder, where SteamVR's path registry isn't: OpenVR and vrcmd need ours.
|
||||||
|
os.environ["XDG_CONFIG_HOME"] = os.path.join(HOME, ".config")
|
||||||
|
|
||||||
versions = current_versions()
|
versions = current_versions()
|
||||||
check_versions(versions)
|
check_versions(versions)
|
||||||
|
|||||||
Reference in new issue
Block a user