Merge pull request #453 from outis1one/claude/steam-non-steam-apps-visibility-p1uqc2

Claude/steam non steam apps visibility p1uqc2
This commit is contained in:
Outis
2026-09-10 10:26:07 -04:00
committed by GitHub
+140 -13
View File
@@ -4071,9 +4071,50 @@ except Exception:
ls "$_SANG_EMU_DIR" 2>/dev/null ls "$_SANG_EMU_DIR" 2>/dev/null
exit 1 exit 1
fi fi
_SANG_EXE="/home/retro/Applications/$(basename "$_SANG_HOST_FILE")" _SANG_REAL_EXE="/home/retro/Applications/$(basename "$_SANG_HOST_FILE")"
[ -z "$_SANG_NAME" ] && _SANG_NAME=$(basename "$_SANG_HOST_FILE" | sed -E 's/\.(AppImage|sh|x86_64)$//I') [ -z "$_SANG_NAME" ] && _SANG_NAME=$(basename "$_SANG_HOST_FILE" | sed -E 's/\.(AppImage|sh|x86_64)$//I')
# Route the actual launch through a small fullscreen-forcing wrapper
# instead of pointing Steam's Exe directly at the AppImage. Why: a
# non-Steam game launched from Steam is a SECOND top-level window in
# Wolf's single-app Steam Sway session (RUN_SWAY=true on the 'steam'
# CATALOG entry) — Sway's own kiosk config only auto-fullscreens the
# ONE window it expects (Steam's own), so anything launched from
# inside Steam opens at whatever default size it requests instead,
# which reads as roughly half the screen against a full
# Moonlight-resolution display. Reported live against ES-DE/Dolphin
# added this way. NOT yet confirmed live that swaymsg actually
# reaches Sway from inside this exact container/session — if it
# doesn't, the wrapper's fullscreen loop just fails silently
# (2>/dev/null below) and the app launches exactly as it did before
# this existed, so this is safe to try without risking the launch
# itself. Regenerated on every call (cheap, stateless — nothing to
# lose by overwriting it) so a fix to the wrapper reaches every
# existing shortcut the next time it's (re-)added, not just new ones.
_SANG_WRAP="$_SANG_EMU_DIR/steam-fullscreen-wrap"
cat > "$_SANG_WRAP" << 'WRAPEOF'
#!/bin/bash
# steam-fullscreen-wrap <real-binary> [args...]
# Launches the real target, then repeatedly asks Sway to fullscreen whatever
# currently has input focus for a few seconds after launch — the newly
# launched window is expected to grab focus once it maps, same as any
# ordinary X11/Wayland client. 'fullscreen enable' (not 'toggle') is
# idempotent, so repeating it while the window is already fullscreen is a
# harmless no-op rather than flipping it back off.
REAL_BIN="$1"; shift
"$REAL_BIN" "$@" &
PID=$!
(
for _i in $(seq 1 20); do
sleep 0.5
swaymsg fullscreen enable 2>/dev/null
done
) &
wait "$PID"
WRAPEOF
chmod +x "$_SANG_WRAP"
_SANG_EXE="/home/retro/Applications/steam-fullscreen-wrap"
STEAM_HOME=$(_steam_home) STEAM_HOME=$(_steam_home)
if [ -z "$STEAM_HOME" ]; then if [ -z "$STEAM_HOME" ]; then
echo "No Steam home found yet under ${WOLF_STATE_DIR:-/etc/wolf}." echo "No Steam home found yet under ${WOLF_STATE_DIR:-/etc/wolf}."
@@ -4100,10 +4141,10 @@ except Exception:
sleep 3 sleep 3
fi fi
sudo python3 - "$_SANG_VDF" "$_SANG_EXE" "$_SANG_NAME" "/home/retro/Applications" << 'VDFPY' sudo python3 - "$_SANG_VDF" "$_SANG_EXE" "$_SANG_NAME" "/home/retro/Applications" "$_SANG_REAL_EXE" << 'VDFPY'
import sys, struct, os, zlib import sys, struct, os, zlib
path, exe_path, app_name, start_dir = sys.argv[1:5] path, exe_path, app_name, start_dir, real_exe = sys.argv[1:6]
TYPE_MAP, TYPE_STR, TYPE_INT, TYPE_END = 0x00, 0x01, 0x02, 0x08 TYPE_MAP, TYPE_STR, TYPE_INT, TYPE_END = 0x00, 0x01, 0x02, 0x08
@@ -4167,13 +4208,30 @@ if shortcuts_entry is None:
entries_list = shortcuts_entry[2] entries_list = shortcuts_entry[2]
# exe_path now points at the shared steam-fullscreen-wrap script (same Exe
# for every emulator added this way), with the real per-emulator target
# carried in LaunchOptions instead — so matching (for both idempotent
# re-adds and appid uniqueness) has to key on the (exe, LaunchOptions) PAIR,
# not exe alone, or adding a second emulator would silently overwrite the
# first one's shortcut entry. Also cleans up a legacy entry from before this
# wrapper existed, where Exe pointed directly at this same real binary with
# no LaunchOptions at all — re-adding an emulator added under the old
# scheme replaces that stale direct-launch entry instead of leaving a
# duplicate tile behind.
quoted_exe = f'"{exe_path}"' quoted_exe = f'"{exe_path}"'
entries_list[:] = [e for e in entries_list if get_field(e[2], 'exe') != quoted_exe] quoted_launch = f'"{real_exe}"'
entries_list[:] = [
e for e in entries_list
if not (
(get_field(e[2], 'exe') == quoted_exe and get_field(e[2], 'LaunchOptions') == quoted_launch)
or get_field(e[2], 'exe') == quoted_launch
)
]
for idx, e in enumerate(entries_list): for idx, e in enumerate(entries_list):
e[0] = str(idx) e[0] = str(idx)
new_index = str(len(entries_list)) new_index = str(len(entries_list))
crc_input = (exe_path + app_name).encode('utf-8') crc_input = (exe_path + real_exe + app_name).encode('utf-8')
appid = (zlib.crc32(crc_input) | 0x80000000) & 0xFFFFFFFF appid = (zlib.crc32(crc_input) | 0x80000000) & 0xFFFFFFFF
appid_signed = appid - 0x100000000 if appid >= 0x80000000 else appid appid_signed = appid - 0x100000000 if appid >= 0x80000000 else appid
@@ -4184,7 +4242,7 @@ new_entry_fields = [
['StartDir', TYPE_STR, f'"{start_dir}"'], ['StartDir', TYPE_STR, f'"{start_dir}"'],
['icon', TYPE_STR, ''], ['icon', TYPE_STR, ''],
['ShortcutPath', TYPE_STR, ''], ['ShortcutPath', TYPE_STR, ''],
['LaunchOptions', TYPE_STR, ''], ['LaunchOptions', TYPE_STR, quoted_launch],
['IsHidden', TYPE_INT, 0], ['IsHidden', TYPE_INT, 0],
['AllowDesktopConfig', TYPE_INT, 1], ['AllowDesktopConfig', TYPE_INT, 1],
['AllowOverlay', TYPE_INT, 1], ['AllowOverlay', TYPE_INT, 1],
@@ -4200,12 +4258,12 @@ entries_list.append([new_index, TYPE_MAP, new_entry_fields])
with open(path, 'wb') as f: with open(path, 'wb') as f:
f.write(serialize_map(root)) f.write(serialize_map(root))
print(f"Wrote shortcuts.vdf: {app_name} -> {exe_path} (appid {appid_signed})") print(f"Wrote shortcuts.vdf: {app_name} -> {real_exe} (via {exe_path}, appid {appid_signed})")
VDFPY VDFPY
sudo chown 1000:1000 "$_SANG_VDF" sudo chown 1000:1000 "$_SANG_VDF"
echo "" echo ""
echo "Added '$_SANG_NAME' -> $_SANG_EXE to Steam's shortcuts.vdf." echo "Added '$_SANG_NAME' -> $_SANG_REAL_EXE (via the fullscreen wrapper) to Steam's shortcuts.vdf."
echo "Open Steam in Moonlight (it will restart since it was stopped above) —" echo "Open Steam in Moonlight (it will restart since it was stopped above) —"
echo "the new tile appears in your Library (may need the Library view, not just Home)." echo "the new tile appears in your Library (may need the Library view, not just Home)."
echo "First launch: right-click it -> Properties -> Compatibility, and confirm" echo "First launch: right-click it -> Properties -> Compatibility, and confirm"
@@ -4701,7 +4759,26 @@ CATALOG = {
# (see below) — without it, an emulator AppImage (Cemu, etc.) # (see below) — without it, an emulator AppImage (Cemu, etc.)
# added as a non-Steam game (./manage.sh steam-add-nonsteam-game) # added as a non-Steam game (./manage.sh steam-add-nonsteam-game)
# has no file to actually point Exe at from inside this container. # has no file to actually point Exe at from inside this container.
f'{games}/emulators:/home/retro/Applications:rw'], f'{games}/emulators:/home/retro/Applications:rw',
# Same roms/saves/bios/retro-home/retroarch mounts as esde/
# retroarch below — without these, a standalone ES-DE or
# RetroArch AppImage added here as a non-Steam game (same
# mechanism as Cemu above) would see none of the ROMs, cores,
# save states, BIOS files, or ES-DE's own settings/custom
# systems (TI-99, Wii U AntiMicroX command) that the esde/
# retroarch containers already have — it'd start from a
# completely empty config instead of reusing what's already
# set up. Every path here is the exact same host directory
# those two containers mount, just also visible from Steam.
f'{games}/roms:/ROMs:rw',
f'{games}/saves:/mnt/games/saves:rw',
f'{games}/media:/media:rw',
f'{games}/bios:/home/retro/bioses:rw',
f'{games}/retro-home:/home/retro/.config:rw',
f'{games}/retro-home-data:/home/retro/.local/share:rw',
f'{games}/retroarch:/home/retro/.config/retroarch:rw',
f'{games}/esde-custom-systems:/home/retro/ES-DE/custom_systems:rw',
f'{games}/esde-settings:/home/retro/ES-DE/settings:rw'],
env=['PROTON_LOG=1', 'RUN_SWAY=true', env=['PROTON_LOG=1', 'RUN_SWAY=true',
'GOW_REQUIRED_DEVICES=/dev/input/* /dev/dri/* /dev/nvidia*'], 'GOW_REQUIRED_DEVICES=/dev/input/* /dev/dri/* /dev/nvidia*'],
cap_add=['SYS_ADMIN', 'SYS_NICE', 'SYS_PTRACE', 'NET_RAW', 'MKNOD', 'NET_ADMIN'], cap_add=['SYS_ADMIN', 'SYS_NICE', 'SYS_PTRACE', 'NET_RAW', 'MKNOD', 'NET_ADMIN'],
@@ -5295,10 +5372,60 @@ controllers per player slot even when the physical controllers are
identical models (the same case \`./manage.sh controllers\` exists to work identical models (the same case \`./manage.sh controllers\` exists to work
around for ES-DE). Add Cemu here, then in Steam's own Big Picture around for ES-DE). Add Cemu here, then in Steam's own Big Picture
Controller Settings you can see and assign each detected controller Controller Settings you can see and assign each detected controller
individually. This hasn't been confirmed live yet against Wolf's individually.
container-created virtual controllers specifically (real hardware behaves
this way; whether Steam Input sees Wolf's virtual joypads the same way is **Controller doesn't respond at all once added to Steam?** Confirmed live:
still to be tested) — worth trying before assuming it works. this is Steam Input, not the emulator — by default Steam applies its own
controller configuration to *every* shortcut, Steam or non-Steam alike,
and a freshly-added non-Steam game with no configuration picked yet can
end up with no usable mapping at all rather than passing raw input
through. Fix from Steam's own Big Picture UI: select the shortcut → the
controller icon / **Manage Game** → **Controller Options**, and either
pick a **Gamepad** template (closest to "pass it through as a normal
joystick", needed for ES-DE/RetroArch's own native SDL input handling to
see it at all) or turn **Steam Input** off for that one shortcut entirely
if you don't need the per-device assignment this section is about in the
first place. This is a one-time, per-shortcut setting Steam remembers —
not something this installer can preconfigure from the command line, since
it's stored in Steam's own (separate, Steam Cloud-synced) controller
config rather than \`shortcuts.vdf\`.
**Opens at roughly half the screen instead of fullscreen?** Also confirmed
live, and now worked around automatically as of the version of this repo
that added the point below — \`steam-add-nonsteam-game\`/
\`steam-setup-frontends\` route the launch through a small wrapper
(\`emulators/steam-fullscreen-wrap\`) instead of pointing Steam's \`Exe\`
directly at the AppImage. The underlying cause: a non-Steam game launched
from Steam is a *second* top-level window inside Wolf's single-app Steam
Sway session, and Sway's own kiosk config only auto-fullscreens the ONE
window it expects (Steam's own) — anything launched from inside Steam
opens at whatever default size it requests instead. The wrapper launches
the real binary, then repeatedly asks Sway to fullscreen whatever currently
has focus for a few seconds after launch (idempotent — harmless if it's
already fullscreen). **This has not been confirmed live against a real
Wolf Steam session yet** — if \`swaymsg\` isn't reachable from inside that
exact container, the wrapper's fullscreen loop just fails silently and the
window opens at its old default size, same as before this existed; it's
safe to try either way since the underlying launch itself is unaffected.
Re-run \`steam-add-nonsteam-game\`/\`steam-setup-frontends\` for anything
already added before this existed — it replaces the old direct-launch
shortcut with the wrapped one automatically, no duplicate tile left behind.
**An added emulator's tile appears in Steam but crashes on launch instead
of opening at all** (as opposed to the half-screen case above, where it
does open): that's a different problem — something about the AppImage
itself failing to run inside the Steam container specifically, since the
same binary launching fine through the \`esde\`/\`desktop\` Wolf apps rules out
the AppImage being broken outright. Worth checking before assuming it's
unfixable:
\`\`\`bash
CONTAINER=\$(docker ps --format '{{.Names}}' | grep -i WolfSteam | head -1)
docker exec "\$CONTAINER" /home/retro/Applications/<the-appimage-file> ; echo "exit: \$?"
\`\`\`
Run directly like this (no wrapper, no Steam involved) the real error
usually prints straight to the terminal — a missing shared library, a
FUSE/AppImage mount failure (\`dlopen(): error loading libfuse.so.2\`),
or similar. That output is what actually narrows down the fix.
## Running ES-DE and/or RetroArch through Steam instead of their own Wolf apps ## Running ES-DE and/or RetroArch through Steam instead of their own Wolf apps
The same Steam Input reasoning above applies beyond just Cemu: ES-DE and The same Steam Input reasoning above applies beyond just Cemu: ES-DE and