#!/bin/bash
# InterGenOS Steam launch wrapper (RT-4).
# Checks that the 32-bit shared libraries Steam needs can actually be
# resolved in the i686 ABI before exec'ing Valve's bootstrap, and refuses
# to launch if they cannot.
#
# WHERE THE REFUSAL GOES. Writing it to stderr alone was not enough: a
# launch from the desktop has no terminal attached and the message went
# nowhere, so a refusal that worked correctly looked to the user like
# nothing happening at all. It hit twice, on 2026-08-05, when a package
# manager cache-rebuild gap left 26 sonames unresolvable. The refusal now
# also goes to the desktop notification service when one is reachable.
# notify-send is NOT a dependency of this package: if it is absent, or
# there is no session bus to talk to, the stderr message is still written
# and the exit status is unchanged.
set -u

MANIFEST="/usr/share/igos/helpers/steam/closure.json"
BOOTSTRAP="/usr/lib/steam/bin_steam.sh"

# refuse <summary> <line>...  — every line to stderr, the summary plus the
# first line to the desktop if that is possible. Never fails the script.
refuse() {
    local summary="$1"; shift
    local first="${1:-}"
    local line
    for line in "$@"; do
        printf 'steam: %s\n' "$line" >&2
    done
    if command -v notify-send >/dev/null 2>&1 \
       && { [ -n "${WAYLAND_DISPLAY:-}" ] || [ -n "${DISPLAY:-}" ]; }; then
        notify-send --app-name=Steam --urgency=critical \
            "$summary" "$first" >/dev/null 2>&1 || true
    fi
}

if [ ! -f "$MANIFEST" ]; then
    refuse "Steam cannot start" \
        "the list of required 32-bit libraries is missing at $MANIFEST." \
        "Reinstall Steam: sudo pkm install steam"
    exit 1
fi
if [ ! -x "$BOOTSTRAP" ] && [ ! -f "$BOOTSTRAP" ]; then
    refuse "Steam is not installed" \
        "the Steam client is not installed yet." \
        "Install it: sudo pkm install steam"
    exit 1
fi

# ldconfig's cache tags a 32-bit lib "(libc6)" and a 64-bit one
# "(libc6,x86-64)". A soname that resolves ONLY as x86-64 is a 32-bit
# gap — exactly what Steam needs and what a naive presence check misses.
# NOTE: `ldconfig -p` lines are TAB-indented, so the name must be
# matched as awk field 1 (a leading-space grep never matches); the tag
# can carry extras ("(libc6, OS ABI: ...)"), so accept any libc6 tag
# NOT marked x86-64 rather than demanding the bare "(libc6)" literal.
# Parse the manifest FIRST and refuse on an empty/unparseable soname
# list — feeding the loop from a silenced python3 would otherwise turn
# a parse failure into a zero-iteration pass (a masked no-op check).
sonames=$(python3 -c "import json; [print(s) for s in json.load(open('$MANIFEST'))['sonames']]" 2>/dev/null)
if [ -z "$sonames" ]; then
    refuse "Steam cannot start" \
        "could not read the list of required 32-bit libraries at $MANIFEST," \
        "or it is empty. Reinstall Steam: sudo pkm install steam"
    exit 1
fi
missing=()
snapshot=$(ldconfig -p)
while IFS= read -r soname; do
    [ -n "$soname" ] || continue
    if ! printf '%s\n' "$snapshot" | awk -v s="$soname" '$1 == s' \
         | grep -v 'x86-64' | grep -q 'libc6'; then
        missing+=("$soname")
    fi
done <<< "$sonames"

if [ "${#missing[@]}" -ne 0 ]; then
    refuse "Steam cannot start" \
        "${#missing[@]} of the 32-bit libraries Steam needs cannot be found." \
        "Reinstall them: sudo pkm install steam" \
        "Missing:"
    for m in "${missing[@]}"; do echo "  - $m" >&2; done
    exit 1
fi

# System-wide Steam compatibility tools (e.g. the ge-proton helper payload
# under /opt/igos/compat-tools). Exported HERE, at the single launch
# chokepoint, rather than via environment.d so a fresh helper install is
# visible to Steam with NO relogin and for every user — an environment.d
# snippet only loads when a login session begins, which is exactly the gap a
# first-time installer hit (Steam already running, snippet unseen). The
# payload lives under /opt (a pressure-vessel-SHAREABLE root); a tool under
# /usr LISTS but can never EXECUTE because /usr is reserved and replaced by
# the container framework (the pv-adverb "No such file" death). Append so a
# user's own value is preserved.
IGOS_COMPAT_TOOLS=/opt/igos/compat-tools
export STEAM_EXTRA_COMPAT_TOOLS_PATHS="${STEAM_EXTRA_COMPAT_TOOLS_PATHS:+$STEAM_EXTRA_COMPAT_TOOLS_PATHS:}$IGOS_COMPAT_TOOLS"

# Game window density. A Proton prefix is created at the Wine default of 96
# dots per inch, so on a display scaled above 1.0 everything Wine draws inside
# a windowed game -- its title bar and its window buttons -- renders at a
# fraction of the size the rest of the desktop uses. igos-game-window-density
# writes a protonfixes hook into this user's configuration; GE-Proton then
# runs that hook for every game and sets the density from inside the prefix,
# which is the only ordering that does not race Wine's own registry flush.
#
# This runs HERE because this wrapper is the one place that executes as the
# person launching Steam, inside their graphical session, at every launch --
# the two conditions for reading the live display scale and for writing into
# that person's own configuration. It rewrites nothing when the value is
# already current, and never touches a hook file the user wrote themselves.
#
# A failure is reported and the launch continues: the density is a comfort
# setting, and refusing to start Steam over it would be the wrong trade. It
# is never silent -- the reason is printed.
if command -v igos-game-window-density >/dev/null 2>&1; then
    if ! igos-game-window-density --quiet sync-hook; then
        echo "steam: could not update the game window density hook (see the message above); starting Steam anyway." >&2
    fi
fi

exec "$BOOTSTRAP" "$@"
