diff --git a/.SRCINFO b/.SRCINFO new file mode 100644 index 0000000..31d1705 --- /dev/null +++ b/.SRCINFO @@ -0,0 +1,20 @@ +pkgbase = deckless-git + pkgdesc = Keep official Steam intact while fixing proxy split, Big Picture rendering, and i3 couch-mode handoff on Linux + pkgver = 0.1.0.r0.g089aa68 + pkgrel = 1 + url = https://github.com/m1ngsama/deckless + arch = any + license = GPL-3.0-or-later + makedepends = git + depends = bash + depends = jq + depends = steam + optdepends = gamescope: run Big Picture inside gamescope + optdepends = gamemode: enable gamemode for Big Picture sessions + optdepends = i3-wm: enable fullscreen handoff between Big Picture and launched games + provides = deckless + conflicts = deckless + source = git+https://github.com/m1ngsama/deckless.git + sha256sums = SKIP + +pkgname = deckless-git diff --git a/CHANGELOG.md b/CHANGELOG.md index 6577700..b731cde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file. The format is inspired by Keep a Changelog, and the project follows semantic versioning once tagged releases begin. +## [Unreleased] + +### Added + +- A `deckless-git` `PKGBUILD` and `.SRCINFO` entry point for Arch users who want to package Deckless from a local clone. +- A real-machine Big Picture screenshot and validation notes in the README. + +### Fixed + +- Wrapper timing around Steam's updater verification so Deckless no longer needs to present a modified wrapper during the verification phase to recover the proxied, GPU-enabled webhelper path. +- Wrapper cleanup now survives Steam's shutdown path by detaching the cleanup helper from the launcher session before Steam exits. + ## [0.1.0] - 2026-03-28 ### Added diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 0000000..7b26124 --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,56 @@ +# Maintainer: m1ngsama + +pkgname=deckless-git +pkgver=0.1.0.r0.g089aa68 +pkgrel=1 +pkgdesc='Keep official Steam intact while fixing proxy split, Big Picture rendering, and i3 couch-mode handoff on Linux' +arch=('any') +url='https://github.com/m1ngsama/deckless' +license=('GPL-3.0-or-later') +depends=('bash' 'jq' 'steam') +makedepends=('git') +optdepends=( + 'gamescope: run Big Picture inside gamescope' + 'gamemode: enable gamemode for Big Picture sessions' + 'i3-wm: enable fullscreen handoff between Big Picture and launched games' +) +provides=('deckless') +conflicts=('deckless') +source=('git+https://github.com/m1ngsama/deckless.git') +sha256sums=('SKIP') + +pkgver() { + cd deckless + git describe --long --tags --abbrev=7 | sed 's/^v//; s/-/.r/; s/-/./' +} + +package() { + cd deckless + + install -d "${pkgdir}/usr/share/deckless" + cp -a \ + LICENSE \ + README.md \ + CHANGELOG.md \ + CONTRIBUTING.md \ + install.sh \ + uninstall.sh \ + bin \ + config \ + docs \ + "${pkgdir}/usr/share/deckless/" + + install -Dm755 /dev/stdin "${pkgdir}/usr/bin/deckless-install" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail + +exec /usr/share/deckless/install.sh "$@" +EOF + + install -Dm755 /dev/stdin "${pkgdir}/usr/bin/deckless-uninstall" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail + +exec /usr/share/deckless/uninstall.sh "$@" +EOF +} diff --git a/README.md b/README.md index 8bf7302..45a73f4 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,26 @@ It started from a real Arch Linux desktop that needed direct game traffic, proxi - Keeps `/usr/bin/steam` as the official upstream client. - Proxies only `steamwebhelper` traffic, so store, community pages, avatars, and embedded web content can use a proxy while games and downloads stay direct. -- Restores the original `steamwebhelper_sniper_wrap.sh` when Steam exits. +- Restores the original `steamwebhelper_sniper_wrap.sh` shortly after Steam exits through a detached cleanup helper. - Removes Steam's `--disable-gpu` and `--disable-gpu-compositing` flags for Big Picture webhelper sessions. - Exports sane `GBM`, `EGL`, and PulseAudio defaults to help Steam stay on hardware acceleration instead of dropping to software rendering. - Launches Big Picture through `gamescope` and `gamemode` when they are available. - Ships an optional i3 bridge that lets a newly launched game take fullscreen from Big Picture and hands fullscreen back when the game exits. - Installs cleanly into XDG paths and can be rolled back with `./uninstall.sh`. +## Real-machine verification + +Validated on March 28, 2026 on an Arch Linux desktop with X11, i3, NVIDIA 595.58.3, and a 240 Hz monitor. + +![Deckless Big Picture running fullscreen on Arch Linux with i3](assets/screenshots/big-picture-arch-i3.png) + +The live validation for this repository confirmed: + +- Steam updater verification completed without a wrapper size mismatch loop. +- The top-level `steamwebhelper` launched with `--proxy-server=...` and without Steam's forced `--disable-gpu*` flags. +- `webhelper_gpu.txt` reported `gpu_compositing: enabled`, `opengl: enabled_on`, and `video_decode: enabled`. +- Big Picture opened as a focused fullscreen `steamwebhelper` window under i3. + ## Design goals - Official Steam first, customization second. @@ -66,11 +79,30 @@ For a controller-first session, launch: steam-bigpicture ``` +## Arch packaging + +This repository also ships a `PKGBUILD` for a rolling `deckless-git` package. + +From a local clone: + +```bash +makepkg -si +deckless-install +``` + +That installs Deckless under `/usr/share/deckless` and exposes: + +- `deckless-install` +- `deckless-uninstall` + ## What gets installed - `~/.local/share/deckless/bin/deckless-steam` - `~/.local/share/deckless/bin/deckless-bigpicture` - `~/.local/share/deckless/bin/deckless-i3-bigpicture-bridge` +- `~/.local/share/deckless/bin/deckless-sync-webhelper-wrapper` +- `~/.local/share/deckless/bin/deckless-webhelper-heal` +- `~/.local/share/deckless/bin/deckless-webhelper-cleanup` - `~/.local/bin/steam` - `~/.local/bin/steam-bigpicture` - `~/.local/share/applications/steam.desktop` @@ -119,6 +151,8 @@ See [docs/i3.md](docs/i3.md) for the handoff behavior. - official `steam` package - X11 - i3 +- NVIDIA proprietary driver 595.58.3 +- 240 Hz display - `gamescope` - `gamemode` - `jq` @@ -129,7 +163,7 @@ Other X11 desktop environments may still benefit from the proxy split and Big Pi - Deckless never replaces `/usr/bin/steam`. - The Steam runtime wrapper is only rewritten while Steam is active. -- The original wrapper is restored after Steam exits. +- The original wrapper is restored shortly after Steam exits, once Steam activity is gone. - `./uninstall.sh` restores the local launchers and desktop entries that existed before the first install. ## Documentation diff --git a/assets/screenshots/big-picture-arch-i3.png b/assets/screenshots/big-picture-arch-i3.png new file mode 100644 index 0000000..ab1e20e Binary files /dev/null and b/assets/screenshots/big-picture-arch-i3.png differ diff --git a/bin/deckless-steam b/bin/deckless-steam index 3168967..a89a5b2 100755 --- a/bin/deckless-steam +++ b/bin/deckless-steam @@ -1,10 +1,11 @@ #!/usr/bin/env bash set -euo pipefail -script_path="$(readlink -f "${BASH_SOURCE[0]}")" +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/deckless" settings_env="${DECKLESS_SETTINGS_ENV:-${config_dir}/deckless.env}" legacy_proxy_env="${HOME}/.config/network/proxy-env.sh" +proxy_env="${DECKLESS_PROXY_ENV:-${config_dir}/proxy-env.sh}" steam_bin="${DECKLESS_STEAM_BIN:-/usr/bin/steam}" if [[ -r "$settings_env" ]]; then @@ -22,7 +23,11 @@ target_dir="${target%/*}" state_dir="${XDG_STATE_HOME:-$HOME/.local/state}/deckless/steam" session_state="${state_dir}/session.env" original_wrapper="${state_dir}/steamwebhelper_sniper_wrap.sh.original" -proxy_env="${DECKLESS_PROXY_ENV:-${config_dir}/proxy-env.sh}" + +sync_helper="${script_dir}/deckless-sync-webhelper-wrapper" +heal_helper="${script_dir}/deckless-webhelper-heal" +cleanup_helper="${script_dir}/deckless-webhelper-cleanup" +cleanup_done=0 if [[ ! -d "$target_dir" ]]; then printf 'Steam runtime directory not found: %s\n' "$target_dir" >&2 @@ -34,30 +39,83 @@ if [[ ! -x "$steam_bin" ]]; then exit 1 fi +for helper in "$sync_helper" "$heal_helper" "$cleanup_helper"; do + if [[ ! -x "$helper" ]]; then + printf 'Deckless helper not found: %s\n' "$helper" >&2 + exit 1 + fi +done + mkdir -p "$state_dir" -terminate_stale_monitors() { +steam_activity_running() { + local args + + while IFS= read -r args; do + if [[ "$args" == *"${steam_root}/ubuntu12_32/steam"* ]] || \ + [[ "$args" == *"${steam_root}/ubuntu12_64/steamwebhelper"* ]] || \ + [[ "$args" == *"${target}"* ]] || \ + [[ "$args" == *"${steam_bin}"* ]]; then + return 0 + fi + done < <(ps -ww -eo args=) + + return 1 +} + +terminate_stale_helpers() { local pid local args - while IFS= read -r line; do - pid="${line%% *}" - args="${line#* }" - [[ "$pid" == "$$" ]] && continue - + while read -r pid args; do case "$args" in - "$script_path"|\ - "$script_path "*|\ - "bash $script_path"|\ - "bash $script_path "*|\ - "/usr/bin/bash $script_path"|\ - "/usr/bin/bash $script_path "*) + "$sync_helper"|\ + "$sync_helper "*|\ + "$heal_helper"|\ + "$heal_helper "*|\ + "$cleanup_helper"|\ + "$cleanup_helper "*|\ + "bash $sync_helper"|\ + "bash $sync_helper "*|\ + "bash $heal_helper"|\ + "bash $heal_helper "*|\ + "bash $cleanup_helper"|\ + "bash $cleanup_helper "*|\ + "/usr/bin/bash $sync_helper"|\ + "/usr/bin/bash $sync_helper "*|\ + "/usr/bin/bash $heal_helper"|\ + "/usr/bin/bash $heal_helper "*|\ + "/usr/bin/bash $cleanup_helper"|\ + "/usr/bin/bash $cleanup_helper "*) kill -TERM "$pid" 2>/dev/null || true ;; esac done < <(ps -ww -eo pid=,args=) } +start_detached_helper() { + local helper="$1" + + if command -v setsid >/dev/null 2>&1; then + setsid -f "$helper" >/dev/null 2>&1 /dev/null 2>&1 /dev/null && [[ -f "$original_wrapper" ]]; then + cp -a "$original_wrapper" "$target" + fi + + rm -f "$session_state" "$original_wrapper" + cleanup_done=1 +} + apply_optional_locale() { if [[ -n "${DECKLESS_LANG:-}" ]]; then while IFS='=' read -r name _; do @@ -127,206 +185,11 @@ build_chromium_bypass_list() { printf '%s\n' "${entries[*]}" } -restore_tracked_wrapper() { - if [[ -f "$original_wrapper" ]]; then - cp -a "$original_wrapper" "$target" - fi -} - -restore_official_wrapper() { - restore_tracked_wrapper - rm -f "$session_state" "$original_wrapper" -} - -write_managed_wrapper() { - local tmp_wrapper - local session_state_q - - tmp_wrapper="$(mktemp "${target_dir}/.steamwebhelper_sniper_wrap.sh.XXXXXX")" - printf -v session_state_q '%q' "$session_state" - - cat >"$tmp_wrapper" <exec ./steamwebhelper \${extra_args[*]} \${forwarded_args[*]}" -echo "" -exec ./steamwebhelper "\${extra_args[@]}" "\${forwarded_args[@]}" -EOF - - chmod 0755 "$tmp_wrapper" - mv -f "$tmp_wrapper" "$target" -} - -ensure_managed_wrapper() { - if grep -Fq 'deckless-managed steam webhelper wrapper' "$target" 2>/dev/null; then - return 0 - fi - - cp -a "$target" "$original_wrapper" - write_managed_wrapper -} - -restart_unproxied_webhelper() { - local pid - local args - local stale=0 - local -a top_level_pids=() - - while IFS= read -r line; do - pid="${line%% *}" - args="${line#* }" - - if [[ "$args" == *'steamwebhelper -nocrashdialog'* ]]; then - stale=0 - if [[ -n "${proxy_server:-}" && "$args" != *'--proxy-server='* ]]; then - stale=1 - fi - if [[ "$args" == *'--disable-gpu '* || "$args" == *'--disable-gpu-compositing'* ]]; then - stale=1 - fi - (( stale == 1 )) && top_level_pids+=("$pid") - elif [[ "$args" == *"${steam_root}/ubuntu12_64/steamwebhelper"* && "$args" != *'--type='* ]]; then - stale=0 - if [[ -n "${proxy_server:-}" && "$args" != *'--proxy-server='* ]]; then - stale=1 - fi - if [[ "$args" == *'--disable-gpu '* || "$args" == *'--disable-gpu-compositing'* ]]; then - stale=1 - fi - (( stale == 1 )) && top_level_pids+=("$pid") - fi - done < <(ps -ww -eo pid=,args=) - - if (( ${#top_level_pids[@]} > 0 )); then - kill -TERM "${top_level_pids[@]}" 2>/dev/null || true - fi -} - -steam_activity_running() { - local args - while IFS= read -r args; do - if [[ "$args" == *"${steam_root}/ubuntu12_32/steam"* ]] || \ - [[ "$args" == *"${steam_root}/ubuntu12_64/steamwebhelper"* ]] || \ - [[ "$args" == *"${target}"* ]] || \ - [[ "$args" == *"${steam_bin}"* ]]; then - return 0 - fi - done < <(ps -ww -eo args=) - return 1 -} - -steam_updater_active() { - local args - while IFS= read -r args; do - if [[ "$args" == *"${steam_root}/ubuntu12_32/steam"* && "$args" == *'-child-update-ui'* ]]; then - return 0 - fi - done < <(ps -ww -eo args=) - return 1 -} - -start_wrapper_monitor() { - ( - local seen_steam=0 - local idle_checks=0 - local startup_checks=0 - - while (( idle_checks < 60 )); do - if steam_activity_running; then - seen_steam=1 - idle_checks=0 - startup_checks=0 - if steam_updater_active; then - if grep -Fq 'deckless-managed steam webhelper wrapper' "$target" 2>/dev/null; then - restore_tracked_wrapper - elif [[ ! -f "$original_wrapper" ]]; then - cp -a "$target" "$original_wrapper" - fi - else - ensure_managed_wrapper - restart_unproxied_webhelper - fi - else - if (( seen_steam == 1 )); then - (( idle_checks += 1 )) - else - (( startup_checks += 1 )) - if (( startup_checks >= 60 )); then - break - fi - fi - fi - sleep 1 - done - - restore_official_wrapper - ) >/dev/null 2>&1 & -} - -terminate_stale_monitors apply_optional_locale if [[ -z "${SDL_VIDEODRIVER:-}" ]]; then @@ -364,12 +227,6 @@ if [[ -n "$bypass_candidate" ]]; then proxy_bypass="$(build_chromium_bypass_list "$bypass_candidate")" fi -if grep -Fq 'deckless-managed steam webhelper wrapper' "$target" 2>/dev/null && [[ -f "$original_wrapper" ]]; then - cp -a "$original_wrapper" "$target" -fi - -cp -a "$target" "$original_wrapper" - tmp_state="$(mktemp "${state_dir}/.session.env.XXXXXX")" trap 'rm -f "${tmp_state:-}"' EXIT { @@ -381,11 +238,22 @@ chmod 0600 "$tmp_state" mv -f "$tmp_state" "$session_state" trap - EXIT -start_wrapper_monitor - unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY unset ALL_PROXY all_proxy unset no_proxy NO_PROXY unset DECKLESS_WEBHELPER_PROXY_SERVER DECKLESS_WEBHELPER_PROXY_BYPASS_LIST -exec "$steam_bin" "$@" +trap 'restore_official_wrapper' EXIT HUP INT TERM + +start_detached_helper "$heal_helper" +start_detached_helper "$cleanup_helper" + +set +e +"$steam_bin" "$@" +steam_status=$? +set -e + +restore_official_wrapper +trap - EXIT HUP INT TERM + +exit "$steam_status" diff --git a/bin/deckless-sync-webhelper-wrapper b/bin/deckless-sync-webhelper-wrapper new file mode 100755 index 0000000..ce08965 --- /dev/null +++ b/bin/deckless-sync-webhelper-wrapper @@ -0,0 +1,104 @@ +#!/usr/bin/env bash +set -euo pipefail + +steam_root="$(readlink -e "$HOME/.steam/steam" || true)" +if [[ -z "$steam_root" ]]; then + steam_root="${XDG_DATA_HOME:-$HOME/.local/share}/Steam" +fi + +target="${steam_root}/ubuntu12_64/steamwebhelper_sniper_wrap.sh" +target_dir="${target%/*}" +state_dir="${XDG_STATE_HOME:-$HOME/.local/state}/deckless/steam" +session_state="${state_dir}/session.env" +original_wrapper="${state_dir}/steamwebhelper_sniper_wrap.sh.original" + +[[ -d "$target_dir" ]] || exit 0 +[[ -f "$target" ]] || exit 0 +[[ -f "$session_state" ]] || exit 0 + +mkdir -p "$state_dir" + +if ! grep -Fq 'deckless-managed steam webhelper wrapper' "$target" 2>/dev/null && [[ ! -f "$original_wrapper" ]]; then + cp -a "$target" "$original_wrapper" +fi + +tmp_wrapper="$(mktemp "${target_dir}/.steamwebhelper_sniper_wrap.sh.XXXXXX")" +trap 'rm -f "$tmp_wrapper"' EXIT + +printf -v session_state_q '%q' "$session_state" + +cat >"$tmp_wrapper" <exec ./steamwebhelper \${extra_args[*]} \${forwarded_args[*]}" +echo "" +exec ./steamwebhelper "\${extra_args[@]}" "\${forwarded_args[@]}" +EOF + +if [[ ! -f "$target" ]] || ! cmp -s "$tmp_wrapper" "$target"; then + chmod 0755 "$tmp_wrapper" + mv -f "$tmp_wrapper" "$target" +fi diff --git a/bin/deckless-webhelper-cleanup b/bin/deckless-webhelper-cleanup new file mode 100755 index 0000000..7a1cdc9 --- /dev/null +++ b/bin/deckless-webhelper-cleanup @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +set -euo pipefail + +steam_root="$(readlink -e "$HOME/.steam/steam" || true)" +if [[ -z "$steam_root" ]]; then + steam_root="${XDG_DATA_HOME:-$HOME/.local/share}/Steam" +fi + +wrapper_target="${steam_root}/ubuntu12_64/steamwebhelper_sniper_wrap.sh" +webhelper_binary="${steam_root}/ubuntu12_64/steamwebhelper" +state_dir="${XDG_STATE_HOME:-$HOME/.local/state}/deckless/steam" +session_state="${state_dir}/session.env" +original_wrapper="${state_dir}/steamwebhelper_sniper_wrap.sh.original" + +[[ -f "$session_state" ]] || exit 0 + +steam_activity_running() { + local args + + while IFS= read -r args; do + if [[ "$args" == *"${steam_root}/ubuntu12_32/steam"* ]] || \ + [[ "$args" == *"${webhelper_binary}"* ]] || \ + [[ "$args" == *"${wrapper_target}"* ]] || \ + [[ "$args" == *'/usr/bin/steam'* ]]; then + return 0 + fi + done < <(ps -ww -eo args=) + + return 1 +} + +restore_wrapper() { + if grep -Fq 'deckless-managed steam webhelper wrapper' "$wrapper_target" 2>/dev/null && [[ -f "$original_wrapper" ]]; then + cp -a "$original_wrapper" "$wrapper_target" + fi + + rm -f "$session_state" "$original_wrapper" +} + +seen_steam=0 +idle_checks=0 +startup_checks=0 + +while (( idle_checks < 30 )); do + if steam_activity_running; then + seen_steam=1 + idle_checks=0 + startup_checks=0 + else + if (( seen_steam == 1 )); then + (( idle_checks += 1 )) + else + (( startup_checks += 1 )) + if (( startup_checks >= 30 )); then + break + fi + fi + fi + + sleep 2 +done + +restore_wrapper diff --git a/bin/deckless-webhelper-heal b/bin/deckless-webhelper-heal new file mode 100755 index 0000000..6c8f235 --- /dev/null +++ b/bin/deckless-webhelper-heal @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" + +steam_root="$(readlink -e "$HOME/.steam/steam" || true)" +if [[ -z "$steam_root" ]]; then + steam_root="${XDG_DATA_HOME:-$HOME/.local/share}/Steam" +fi + +wrapper_target="${steam_root}/ubuntu12_64/steamwebhelper_sniper_wrap.sh" +webhelper_binary="${steam_root}/ubuntu12_64/steamwebhelper" +state_dir="${XDG_STATE_HOME:-$HOME/.local/state}/deckless/steam" +session_state="${state_dir}/session.env" +sync_helper="${script_dir}/deckless-sync-webhelper-wrapper" + +[[ -f "$session_state" ]] || exit 0 +[[ -x "$sync_helper" ]] || exit 0 + +proxy_server='' +if [[ -r "$session_state" ]]; then + # shellcheck disable=SC1090 + . "$session_state" + proxy_server="${DECKLESS_WEBHELPER_PROXY_SERVER:-}" +fi + +webhelper_args_healthy() { + local args="$1" + + if [[ -n "$proxy_server" && "$args" != *'--proxy-server='* ]]; then + return 1 + fi + + if [[ "$args" == *'--disable-gpu '* || "$args" == *'--disable-gpu-compositing'* ]]; then + return 1 + fi + + return 0 +} + +attempt=0 +while (( attempt < 180 )); do + top_level_pids=() + wrap_pids=() + healthy=0 + + while read -r pid args; do + if [[ "$args" == *"${wrapper_target}"* ]]; then + wrap_pids+=("$pid") + fi + + if [[ "$args" == *'steamwebhelper -nocrashdialog'* ]]; then + if webhelper_args_healthy "$args"; then + healthy=1 + break + fi + top_level_pids+=("$pid") + elif [[ "$args" == *"${webhelper_binary}"* && "$args" != *'--type='* ]]; then + if webhelper_args_healthy "$args"; then + healthy=1 + break + fi + top_level_pids+=("$pid") + fi + done < <(ps -ww -eo pid=,args=) + + (( healthy == 1 )) && exit 0 + + if (( ${#wrap_pids[@]} > 0 || ${#top_level_pids[@]} > 0 )); then + "$sync_helper" || exit 0 + + if (( ${#wrap_pids[@]} > 0 )); then + kill -TERM "${wrap_pids[@]}" 2>/dev/null || true + fi + + if (( ${#top_level_pids[@]} > 0 )); then + kill -TERM "${top_level_pids[@]}" 2>/dev/null || true + fi + + exit 0 + fi + + sleep 1 + (( attempt += 1 )) +done diff --git a/docs/architecture.md b/docs/architecture.md index 05f27bf..ae8a675 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -15,9 +15,22 @@ This is the main launcher. - resolves the active Steam runtime path - sources optional Deckless config - loads proxy settings -- writes a session-only replacement for `steamwebhelper_sniper_wrap.sh` +- writes session state for helper processes +- starts a healer that waits for the first Steam webhelper hop and then patches `steamwebhelper_sniper_wrap.sh` - clears proxy environment variables before starting the official Steam client -- restores the original wrapper after Steam exits +- starts a detached cleanup worker that restores the original wrapper after Steam exits + +### `deckless-sync-webhelper-wrapper` + +This helper writes the managed `steamwebhelper_sniper_wrap.sh` replacement for the current session and captures the official upstream wrapper before replacing it. + +### `deckless-webhelper-heal` + +This helper waits for the first top-level `steamwebhelper` launch, checks whether proxy and GPU policy landed, and re-launches it once through the managed wrapper when needed. + +### `deckless-webhelper-cleanup` + +This helper runs detached from the launcher session, waits until Steam activity is gone, restores the official wrapper, and removes the session backup. ### `deckless-bigpicture` @@ -29,7 +42,7 @@ This bridge listens to i3 window events and hands fullscreen from Big Picture to ## Why patch the Steam webhelper wrapper at runtime -Steam itself already uses `steamwebhelper_sniper_wrap.sh` as the last hop before `steamwebhelper`. Replacing that wrapper only while Steam is running gives Deckless a narrow control point for: +Steam itself already uses `steamwebhelper_sniper_wrap.sh` as the last hop before `steamwebhelper`. Replacing that wrapper only after Steam reaches the webhelper launch phase gives Deckless a narrow control point for: - webhelper-only proxy flags - removing forced `--disable-gpu` arguments diff --git a/install.sh b/install.sh index 23cfe27..a32ca8d 100755 --- a/install.sh +++ b/install.sh @@ -124,6 +124,9 @@ backup_once "${autostart_dir}/deckless-i3-bigpicture-bridge.desktop" "autostart/ install -Dm755 "${repo_root}/bin/deckless-steam" "${install_root}/bin/deckless-steam" install -Dm755 "${repo_root}/bin/deckless-bigpicture" "${install_root}/bin/deckless-bigpicture" install -Dm755 "${repo_root}/bin/deckless-i3-bigpicture-bridge" "${install_root}/bin/deckless-i3-bigpicture-bridge" +install -Dm755 "${repo_root}/bin/deckless-sync-webhelper-wrapper" "${install_root}/bin/deckless-sync-webhelper-wrapper" +install -Dm755 "${repo_root}/bin/deckless-webhelper-heal" "${install_root}/bin/deckless-webhelper-heal" +install -Dm755 "${repo_root}/bin/deckless-webhelper-cleanup" "${install_root}/bin/deckless-webhelper-cleanup" install -Dm644 "${repo_root}/config/proxy-env.example.sh" "${config_dir}/proxy-env.example.sh" install -Dm644 "${repo_root}/config/deckless.env.example" "${config_dir}/deckless.env.example"