mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-24 14:01:46 +02:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f718273a5 | ||
|
|
4e456480ae | ||
|
|
241f538f99 | ||
|
|
21dacfcbe7 |
No files matched your search
@@ -2,6 +2,11 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Distinguish an unreadable gamescope panel list from a confirmed empty list in
|
||||
Desktop Capture and Control (issue #73). Failed discovery now asks users to
|
||||
check SteamVR and report the exact message and SteamOS version, rather than
|
||||
claiming no panel is open. This does not establish a new capture fix.
|
||||
|
||||
- Add an opt-in desktop low-battery alert without starting a family session.
|
||||
Existing status reads confirm low charge and drain; recovery hysteresis and a
|
||||
ten-minute cooldown limit repeat alerts. Off on page open/headset switch;
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "frame-control",
|
||||
"version": "0.4.16",
|
||||
"version": "0.4.17",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "frame-control",
|
||||
"version": "0.4.16",
|
||||
"version": "0.4.17",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"electron": "^44.4.5",
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "frame-control",
|
||||
"productName": "Frame Control",
|
||||
"version": "0.4.16",
|
||||
"version": "0.4.17",
|
||||
"description": "Desktop app for managing a Valve Steam Frame over SSH",
|
||||
"private": true,
|
||||
"main": "main.js",
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"date_utc": "2026-10-24",
|
||||
"version": "v0.4.17",
|
||||
"steam_os_version": "0.5.6",
|
||||
"steam_os_build": "20261015.6141207",
|
||||
"result": "PASS: the real Steam-saved clip exported beyond 60 seconds",
|
||||
"method": "Steam manual recording of a reserved test title, then Frame Control's production frame_clips.export_clip path; no packaged GUI button click",
|
||||
"source": {
|
||||
"kind": "saved Steam clip",
|
||||
"duration_seconds": 100.801,
|
||||
"chunks": 68,
|
||||
"gaps": 0
|
||||
},
|
||||
"export": {
|
||||
"format": "MP4",
|
||||
"bytes": 1377849,
|
||||
"sha256": "82ef31f65e6933d122bc326d664beb2eb2e3ba6969f26c0032552e80fbe8d823",
|
||||
"duration_seconds_ffprobe": 100.833335,
|
||||
"video": "H.264, 1920x1080, 6049 frames",
|
||||
"audio": "AAC, 48000 Hz, stereo",
|
||||
"full_ffmpeg_decode": "passed without errors"
|
||||
},
|
||||
"cleanup": "Restored Steam recording mode to its prior off setting; stopped and removed only the reserved title and its processes; no recording or running Steam apps remained; Game Mode active, battery 100%, shared test lock released",
|
||||
"limits": [
|
||||
"This exercised the production export code path, not a packaged GUI Export click.",
|
||||
"Visible gameplay quality, perceptual audio/video sync, trims and longer recordings were not checked.",
|
||||
"The newly saved Steam source clip was retained; no user recording was deleted."
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
# Linux PC host feasibility on lxso2, 2026-10-24
|
||||
|
||||
**Blocked on this host's current desktop environment. No feature enabled and
|
||||
no feature PR opened.** Investigation for [issue #23](https://github.com/saphid/frame-control/issues/23),
|
||||
starting at `4e45648` (main after #154). This concerns flat desktop panels,
|
||||
not Linux PC VR streaming.
|
||||
|
||||
## Decision
|
||||
|
||||
The smallest useful candidate is one explicitly selected **whole screen**,
|
||||
captured through the ScreenCast portal's restricted PipeWire connection,
|
||||
encoded locally with GStreamer/x264, and sent to the existing viewer through
|
||||
the shared SSH controller. Input, individual windows and virtual displays
|
||||
would remain unsupported until separately verified. This candidate was **not
|
||||
implemented**: lxso2 currently cannot exercise the real capture permission path.
|
||||
|
||||
Development packages could unblock compilation, but would not create a desktop,
|
||||
portal backend or consented screen. Synthetic encoding, an Xvfb screen grab or
|
||||
using the Frame as its own host would not verify Linux PC desktop capture.
|
||||
No host packages or services were changed.
|
||||
|
||||
## Evidence
|
||||
|
||||
Host: `lxso2`, Linux x86-64, kernel `6.8.0-139-generic`.
|
||||
|
||||
- `DISPLAY`, `WAYLAND_DISPLAY` and `XDG_SESSION_TYPE` were unset. The user bus
|
||||
was reachable at `/run/user/1000/bus`.
|
||||
- `/run/user/1000/pipewire-0` and `/run/user/1000/wayland-0` did not exist.
|
||||
No processes matched Xorg, Xwayland, Xvfb, GNOME Shell, KWin Wayland, Weston,
|
||||
PipeWire, WirePlumber or xdg-desktop-portal at the process check.
|
||||
- D-Bus `ListNames` returned D-Bus, systemd and anonymous connections, with no
|
||||
`org.freedesktop.portal.Desktop`. `ListActivatableNames` also had no desktop
|
||||
portal. These calls queried D-Bus itself without activating capture services.
|
||||
- `dpkg-query` found no `xdg-desktop-portal*` or `pipewire*` packages.
|
||||
`libgstreamer1.0-0:amd64` was installed at `1.24.2-1ubuntu0.1`, but
|
||||
`gstreamer1.0-tools` was uninstalled. `gst-launch-1.0` and `gst-inspect-1.0`
|
||||
were absent from PATH. Xvfb was installed, but supplies no portal by itself.
|
||||
- `pkg-config --modversion` failed for `gstreamer-1.0`,
|
||||
`gstreamer-app-1.0`, `gstreamer-video-1.0` and `libpipewire-0.3`.
|
||||
`gio-unix-2.0` reported `2.80.0`.
|
||||
- `desktop/bundle/pc-host.so` did not exist.
|
||||
`python3 desktop/build.py --with-x264 --out /tmp/frame-linux-pc-feasibility`
|
||||
exited **1** before compilation: required GStreamer pkg-config modules were
|
||||
missing. No native build or encoder runtime success is claimed.
|
||||
|
||||
Reproduce the non-activating portal checks in the intended desktop user's
|
||||
session, using that session's actual runtime directory and bus:
|
||||
|
||||
```sh
|
||||
gdbus call --session --dest org.freedesktop.DBus \
|
||||
--object-path /org/freedesktop/DBus --method org.freedesktop.DBus.ListNames
|
||||
gdbus call --session --dest org.freedesktop.DBus \
|
||||
--object-path /org/freedesktop/DBus --method org.freedesktop.DBus.ListActivatableNames
|
||||
pkg-config --modversion gstreamer-1.0 gstreamer-app-1.0 gstreamer-video-1.0 gio-unix-2.0
|
||||
```
|
||||
|
||||
## Existing implementation reviewed
|
||||
|
||||
- `ui/frame_pcview.py` selects PCView only on Windows and rejects Linux even
|
||||
when enabled. Linux installers do not carry its native bundle.
|
||||
- `desktop/portal.c` creates a **RemoteDesktop** session, requests pointer and
|
||||
keyboard devices, and selects monitors and windows (`types=3`). It is not
|
||||
ScreenCast-only or screen-only. Its restricted fd/node and fresh-connection
|
||||
handling are reusable.
|
||||
- `ui/frame_pc_agent.py` calls the selection a shared window or screen and
|
||||
picks VA-API when the element is present, falling back to x264. A bounded
|
||||
x264 slice needs explicit encoder policy and unsupported-input behavior;
|
||||
exposing the existing Linux path alone would not meet that scope.
|
||||
- `app/main.js` starts Python with the inherited environment; it does not
|
||||
supply a compositor, portal backend or capture permission.
|
||||
- `.github/workflows/pc-host.yml` installs native dependencies and tests
|
||||
synthetic x264/protocol behavior with fake capture consent/input. This does
|
||||
not establish interactive Linux desktop capture.
|
||||
- Issue #23 and its six existing comments distinguish prior synthetic
|
||||
helper/viewer results from untested Linux desktop capture and consent.
|
||||
|
||||
## Verification and limits
|
||||
|
||||
`python3 -m unittest discover -s tests -p 'test_pc*.py' -v` exited **0**:
|
||||
27 tests ran successfully, with one additional native-class setup skip
|
||||
(`native PC libraries not built on this host`). Coverage includes the compiled
|
||||
C controller trace, Python adapters, grants and default-off/Windows-only gates.
|
||||
It does not prove native GStreamer capture or local-client streaming.
|
||||
|
||||
No fake/local native stream, consent prompt, real desktop capture, Frame viewer
|
||||
run, benchmark, input or window mode was tested in this investigation. No SSH
|
||||
connection to the Frame was needed; no lock was acquired and no headset install,
|
||||
launch, stop or settings change was attempted. Issue #113 was left alone.
|
||||
No issue comments or other public messages were sent.
|
||||
|
||||
## Concrete unblock and next slice
|
||||
|
||||
1. Supply an interactive Linux desktop, physical or VM, with a working
|
||||
ScreenCast portal/backend, PipeWire and accessible consent dialog. Installing
|
||||
the portal frontend alone is insufficient. A VM can establish software
|
||||
capture/x264 behavior while physical-host behavior remains unverified.
|
||||
2. Install the native dependencies listed in `pc-host.yml` in that environment
|
||||
and build a local `--with-x264` bundle. Resolve x264 distribution
|
||||
licensing/source obligations before shipping it: the current build labels
|
||||
that option test-only and the Windows installer omits it.
|
||||
3. Implement a ScreenCast-only session with monitor-only selection, no
|
||||
RemoteDesktop/device request, disabled input in protocol and viewer, hidden
|
||||
window/virtual-display modes, and explicit x264 selection. Preserve the
|
||||
default-off gate and existing Mac/Windows paths.
|
||||
4. Verify consent acceptance/refusal/cancellation, Stop/reopen, connection loss
|
||||
and portal closure with a local client decoding actual captured content.
|
||||
Run the shared benchmark and record results without inferring hardware or
|
||||
physical laser behavior.
|
||||
5. Only after local capture works, acquire the shared Frame lock once and
|
||||
follow [the headset procedure](../testing.md#headset-smoke-test) for a brief
|
||||
viewer test. If occupied, leave the lock alone and defer device testing.
|
||||
|
||||
These are prerequisites and proposed scope, not a ready feature. The Linux
|
||||
host request in #23 remains open.
|
||||
@@ -0,0 +1,65 @@
|
||||
# Panel discovery investigation, 2026-10-24
|
||||
|
||||
Base: v0.4.16 (`040581a`). Scope: issue #73, Desktop Capture and Control.
|
||||
|
||||
## Evidence and change
|
||||
|
||||
Issue #73 reports SteamOS 0.4.5 with its desktop visibly running, without a
|
||||
Frame Control version or steps. The maintainer's 2026-10-12 comment identifies
|
||||
the duplicate `loadPanels` UI function fixed in 0.4.3 and requests the exact
|
||||
remaining message and SteamOS build if it persists. There is no reporter
|
||||
follow-up. At this base, the functions are distinct and the existing Node
|
||||
regression checks their uniqueness and the Desktop GET request.
|
||||
|
||||
Read-only source inspection found a remaining diagnostic ambiguity:
|
||||
`read_props()` returns `{}` for failed/timed-out X queries and missing root
|
||||
properties. `panels()` treated that like a confirmed empty focusable-window
|
||||
list. With no detected Plasma process it claimed no panel was open; with Plasma
|
||||
it claimed SteamOS was not listing the desktop. Neither claim follows from an
|
||||
unreadable list.
|
||||
|
||||
The change checks for the presence of `GAMESCOPE_FOCUSABLE_WINDOWS` before
|
||||
those claims. An absent list now reports unknown panel state, suggests checking
|
||||
SteamVR and retrying/Headset view, and asks for the exact message and SteamOS
|
||||
version if persistent. Missing-tool and whole-run deadline explanations retain
|
||||
precedence. No new probes, retries, timeouts, input or capture routes are added.
|
||||
|
||||
## Real-device boundary
|
||||
|
||||
A preliminary read-only SSH inspection returned SteamOS 0.5.6, BUILD_ID
|
||||
`20261015.6141207`, battery 99%, discharging, and X0/X1 socket names. It made
|
||||
no headset changes. The shared lock was absent at that moment.
|
||||
|
||||
The subsequent atomic `mkdir /tmp/frame-test.lock` failed with `File exists`.
|
||||
The guarded command exited with status 3 before the session, X-property or
|
||||
panel-helper probes ran. The other task's lock was left alone. No application
|
||||
was installed, started, stopped or focused; no headset settings changed.
|
||||
|
||||
That implementation probe was blocked by the occupied shared device. The
|
||||
coordinator later supplied a separate narrow read-only observation on SteamOS
|
||||
0.5.6, BUILD_ID `20261015.6141207`, at battery 99%, with the shared lock absent
|
||||
and both `xprop` and `xwininfo` installed:
|
||||
|
||||
- In **Game Mode**, `DISPLAY=:0 xprop -root GAMESCOPE_FOCUSABLE_WINDOWS
|
||||
GAMESCOPE_FOCUSED_WINDOW` returned both properties **present but empty**.
|
||||
- On `DISPLAY=:1`, both properties were reported **not found**.
|
||||
|
||||
This observation distinguishes a confirmed empty list on `:0` from absent
|
||||
properties on `:1`. It does **not** reproduce #73's Desktop Mode report on
|
||||
SteamOS 0.4.5, and it does **not** test this PR's code on the headset. It is a
|
||||
coordinator-supplied observation, separate from the blocked implementation probe
|
||||
above; no new headset probe was run for this follow-up.
|
||||
|
||||
Remaining limit: there is no reproduction establishing a further
|
||||
capture/discovery fix for the reported Desktop Mode/build combination. This PR
|
||||
improves a demonstrated diagnostic error; it must not close #73 as a verified
|
||||
new capture fix.
|
||||
|
||||
## Offline verification
|
||||
|
||||
Focused Python regressions distinguish absent, focus-only, failed/timed-out X
|
||||
queries, confirmed empty and desktop-running lists. Existing tests cover
|
||||
missing tools, alternate displays, successful discovery and the 12-second
|
||||
deadline. The production page's Node behavior test verifies that both Capture
|
||||
and Control preserve the unreadable-list advice. These use fake X/HTTP/DOM
|
||||
boundaries and do not prove real SteamOS 0.4.5 capture or physical input.
|
||||
@@ -107,6 +107,12 @@ The Linux adapter from #38 (desktop portal, PipeWire, VA-API) is in the tree,
|
||||
because it shares `capture.c` and the controller, and CI still builds and tests
|
||||
it. The app never offers it and the Linux installers don't include it.
|
||||
|
||||
The [2026-10-24 lxso2 feasibility check](evidence/linux-pc-host-lxso2-2026-10-24.md)
|
||||
found no running or activatable desktop portal, no PipeWire socket and missing
|
||||
native build dependencies. Linux support remains disabled. The evidence records
|
||||
the build failure and prerequisites for a screen-only, view-only x264 slice;
|
||||
Linux capture, input and window modes have not been verified there.
|
||||
|
||||
## Measuring
|
||||
|
||||
The Mac benchmark accepts the PC host:
|
||||
|
||||
+15
-3
@@ -170,14 +170,26 @@ The temporary server stopped, the shared device lock was released, and the
|
||||
headset remained in Game Mode at 99% battery. See
|
||||
[`docs/evidence/clip-gui-export-2026-10-24.json`](evidence/clip-gui-export-2026-10-24.json)
|
||||
for the narrow proof. This did not exercise the packaged desktop installer.
|
||||
|
||||
On 2026-10-24, the exact v0.4.17 tag exported a second real Steam-saved clip
|
||||
through `frame_clips.export_clip`, the same production path used by **Export**.
|
||||
Steam listed the clip at **100.801 seconds**, with 68 chunks and no gaps. The
|
||||
copied MP4 was **100.833 seconds** by `ffprobe` and decoded completely with
|
||||
`ffmpeg`; it was not cut at 60 seconds. The test restored Steam's recording
|
||||
mode, removed its reserved title and processes, and left Game Mode active at
|
||||
100% battery. See [the long-clip evidence](evidence/clip-long-2026-10-24.json).
|
||||
This did not click **Export** in the packaged desktop app or verify visible
|
||||
gameplay quality or perceptual audio/video sync.
|
||||
|
||||
Remaining checks include:
|
||||
|
||||
- Perceptual audio/video sync and audible content. Frame Control's separate
|
||||
**Record** path stamps camera and audio inputs with the wall clock because
|
||||
they otherwise count from different clocks.
|
||||
- Long saved clips, trims starting partway through a Steam recording, and the
|
||||
packaged desktop app's **Export** button. One real saved clip's directory
|
||||
layout was checked; the parser remains deliberately loose for other layouts.
|
||||
- Clips longer than the 100-second test, trims starting partway through a Steam
|
||||
recording, and the packaged desktop app's **Export** button. Two real saved
|
||||
clips' directory layouts were checked; the parser remains deliberately loose
|
||||
for other layouts.
|
||||
- How much x264 at 1080p30 costs the Frame while a game is running.
|
||||
- Automatic copying: that 30 seconds without a write is a safe sign Steam has
|
||||
finished saving a clip, and how a once-a-minute listing feels on the Frame.
|
||||
@@ -7,6 +7,9 @@ This covers three directions, plus input:
|
||||
- **C. iPhone → Frame**: mirror the phone inside the headset.
|
||||
- **PC VR from Linux**: [feasibility and options](linux-vr-streaming.md),
|
||||
including Valve's streaming and USB support. No Linux host tested yet.
|
||||
- **Linux desktop → Frame panels**: [PC-host feasibility on lxso2](evidence/linux-pc-host-lxso2-2026-10-24.md).
|
||||
Blocked on missing desktop portal/PipeWire and native build dependencies;
|
||||
Linux desktop capture remains disabled and unverified.
|
||||
- **Input**: type and point in the Frame from the Mac or iPhone.
|
||||
- **Live view and Control**: watch a panel flat and tap on it to use it.
|
||||
|
||||
@@ -285,6 +288,13 @@ How (**verified 2026-09-29**, SteamOS 0.4.1, build 20260925.6191901):
|
||||
[#73](https://github.com/saphid/frame-control/issues/73) (SteamOS 0.4.5, desktop
|
||||
open but not found). The likely cause there was the page itself: a second
|
||||
`loadPanels` (the panel switcher's) replaced the Desktop view's, fixed in #84.
|
||||
If the `GAMESCOPE_FOCUSABLE_WINDOWS` property cannot be read, discovery now
|
||||
reports that the panel list is unreadable and whether a panel is open is
|
||||
unknown. A failed X connection or missing property is not evidence that the
|
||||
desktop is closed. Check that SteamVR is running, retry or use Headset view;
|
||||
if it persists, report the exact message and SteamOS version. The confirmed
|
||||
empty-list advice is retained when the property is present but empty.
|
||||
[2026-10-24 investigation and verification limits](evidence/panel-discovery-2026-10-24.md).
|
||||
- Tested from the iPhone app (Simulator): a tap on the Desktop view focused a
|
||||
text box in the panel and the text field typed into it; a trackpad move went
|
||||
exactly (+40, +25).
|
||||
|
||||
@@ -40,6 +40,15 @@ function page(answer) {
|
||||
if (!p.noPanelWhy().startsWith("The headset's desktop is running")) fail("why for capture: " + p.noPanelWhy());
|
||||
if (!p.ctrlTarget().why.startsWith("The headset's desktop is running")) fail("why for control: " + p.ctrlTarget().why);
|
||||
}
|
||||
// An unreadable list is unknown: both Capture and Control retain that distinction.
|
||||
{
|
||||
const why = "Frame Control couldn't read gamescope's panel list, so it can't tell whether an app panel is open. " +
|
||||
"Check that SteamVR is running in the headset, then try again or use the Headset view. " +
|
||||
"If this persists, report your SteamOS version and this exact message.";
|
||||
const p = page(() => ({ panels: [], focus: null, why }));
|
||||
await p.loadPanels();
|
||||
if (p.noPanelWhy() !== why || p.ctrlTarget().why !== why) fail("unreadable list reason lost");
|
||||
}
|
||||
// An older headset script without "why": the generic advice.
|
||||
{
|
||||
const p = page(() => ({ panels: [], focus: null }));
|
||||
|
||||
@@ -355,6 +355,8 @@ class FindingPanels(unittest.TestCase):
|
||||
t.subprocess.run = lambda *a, **k: subprocess.CompletedProcess(a, 0, out, "")
|
||||
self.assertEqual(self.real_read_props(":0"), {"GAMESCOPE_FOCUSABLE_WINDOWS": [1, 0, 2, 3, 769, 4],
|
||||
"GAMESCOPE_FOCUSED_WINDOW": [0]})
|
||||
t.subprocess.run = lambda *a, **k: subprocess.CompletedProcess(a, 0, "GAMESCOPE_FOCUSABLE_WINDOWS(CARDINAL) = \n", "")
|
||||
self.assertEqual(self.real_read_props(":0"), {"GAMESCOPE_FOCUSABLE_WINDOWS": []})
|
||||
t.subprocess.run = lambda *a, **k: subprocess.CompletedProcess(a, 0, "GAMESCOPE_FOCUSED_WINDOW: not found.\n", "")
|
||||
self.assertEqual(self.real_read_props(":0"), {})
|
||||
|
||||
@@ -392,17 +394,52 @@ class FindingPanels(unittest.TestCase):
|
||||
self.assertIn("Headset view", out["why"])
|
||||
|
||||
def test_desktop_running_but_not_listed(self):
|
||||
self.props[(":0", "GAMESCOPE_FOCUSABLE_WINDOWS")] = []
|
||||
self.t.desktop_running = lambda: True
|
||||
out = self.t.panels()
|
||||
self.assertEqual(out["panels"], [])
|
||||
self.assertIn("desktop is running", out["why"])
|
||||
|
||||
def test_nothing_open(self):
|
||||
self.props[(":0", "GAMESCOPE_FOCUSABLE_WINDOWS")] = []
|
||||
out = self.t.panels()
|
||||
self.assertEqual(out, {"focus": None, "focus_display": None, "panels": [],
|
||||
"why": "No app panel is open in the headset. Open the desktop or an app in "
|
||||
"the headset, then try again."})
|
||||
|
||||
def test_absent_list_is_unknown_even_when_desktop_is_running(self):
|
||||
for desktop in (False, True):
|
||||
with self.subTest(desktop=desktop):
|
||||
self.t.desktop_running = lambda: desktop
|
||||
self.t._ROOT.clear()
|
||||
out = self.t.panels()
|
||||
self.assertEqual(out["panels"], [])
|
||||
self.assertIn("couldn't read gamescope's panel list", out["why"])
|
||||
self.assertIn("can't tell whether", out["why"])
|
||||
self.assertIn("Headset view", out["why"])
|
||||
self.assertNotIn("No app panel is open", out["why"])
|
||||
|
||||
def test_focus_property_without_panel_list_is_unknown(self):
|
||||
self.props[(":0", "GAMESCOPE_FOCUSED_WINDOW")] = [0]
|
||||
self.assertIn("couldn't read gamescope's panel list", self.t.panels()["why"])
|
||||
|
||||
def test_failed_xprop_does_not_claim_no_panels_are_open(self):
|
||||
t = self.t
|
||||
t.read_props = self.real_read_props
|
||||
saved = t.subprocess.run
|
||||
self.addCleanup(setattr, t.subprocess, "run", saved)
|
||||
for failure in ("refused", "timeout"):
|
||||
with self.subTest(failure=failure):
|
||||
def run(*args, **kwargs):
|
||||
if failure == "timeout":
|
||||
raise subprocess.TimeoutExpired(args[0], kwargs["timeout"])
|
||||
return subprocess.CompletedProcess(args[0], 1, "", "Can't open display")
|
||||
t.subprocess.run = run
|
||||
t._ROOT.clear()
|
||||
out = t.panels()
|
||||
self.assertIn("couldn't read gamescope's panel list", out["why"])
|
||||
self.assertNotIn("No app panel is open", out["why"])
|
||||
|
||||
def test_missing_x_tools_are_named(self):
|
||||
self.plasma_on(":0")
|
||||
self.t.shutil.which = lambda tool: None if tool == "xwininfo" else "/usr/bin/" + tool
|
||||
|
||||
+8
-3
@@ -271,7 +271,7 @@ def panels(limit=None):
|
||||
out["why"] = ("The headset took too long to list its panels (its X tools didn't answer in time). "
|
||||
+ ("Some may be missing. " if found else "") + "Try again, or use the Headset view.")
|
||||
elif not found:
|
||||
out["why"] = why_none(unfound)
|
||||
out["why"] = why_none(unfound, props)
|
||||
return out
|
||||
|
||||
|
||||
@@ -295,13 +295,18 @@ def desktop_running():
|
||||
return False
|
||||
|
||||
|
||||
def why_none(listed):
|
||||
def why_none(listed, props):
|
||||
"""Why panels() found nothing, in words the person at the computer can act on.
|
||||
listed: how many of the windows gamescope lists aren't X11 windows on any display."""
|
||||
listed: how many of the windows gamescope lists aren't X11 windows on any display.
|
||||
props: the root properties actually read; an absent list is not an empty list."""
|
||||
missing = [tool for tool in ("xprop", "xwininfo") if not shutil.which(tool)]
|
||||
if missing:
|
||||
return (f"This SteamOS build has no {' or '.join(missing)}, which Frame Control uses to find the "
|
||||
"headset's panels. Use the Headset view instead, and please report your SteamOS version.")
|
||||
if "GAMESCOPE_FOCUSABLE_WINDOWS" not in props:
|
||||
return ("Frame Control couldn't read gamescope's panel list, so it can't tell whether an app panel is open. "
|
||||
"Check that SteamVR is running in the headset, then try again or use the Headset view. "
|
||||
"If this persists, report your SteamOS version and this exact message.")
|
||||
if listed:
|
||||
# gamescope lists windows, but none is an X11 window on any display: a Wayland
|
||||
# window (a desktop drawn straight to gamescope, say) can't be found or captured this way.
|
||||
|
||||
Reference in new issue
Block a user