Force ES-DE's "Run in background" off durably; mount ~/ES-DE/settings

Fixes a real, confirmed-live, cross-system bug: with ES-DE's "Run in
background (while game is launched)" enabled, ES-DE keeps listening to
every controller even after a game/emulator takes focus - a second
controller's input can reach ES-DE's own menu and launch a completely
different game underneath whatever's already running. ES-DE's own
USERGUIDE.md names this exact failure mode.

ES-DE's compiled default for this setting is already off (confirmed
against its real Settings.cpp), but nothing in this repo asserted that
durably, and ~/ES-DE (settings, gamelists, scraped media, logs) had no
mount onto the game drive at all - confirmed against ES-DE's own source
(getAppDataDirectory() is a plain $HOME/ES-DE) and GOW's own es-de
startup script. Wolf normally reuses the same app container across
sessions rather than recreating it each time (confirmed against Wolf's
docker.cpp - it only removes the container on exit if
WOLF_STOP_CONTAINER_ON_EXIT=TRUE, which this repo never sets), so this
mostly didn't bite day to day, but it meant the setting - and everything
else under ~/ES-DE - wasn't safe across an actual reinstall the way
roms/saves/BIOS already are.

Mounts esde-settings/ onto ~/ES-DE/settings specifically (additive,
doesn't touch the existing custom_systems mount) and writes a surgical,
idempotent RunInBackground=false into es_settings.xml on every install -
never a full rewrite, since that file is the user's own complete
settings state. Verified the write logic against fresh-file, existing-
file-with-other-settings, and flip-an-existing-true-to-false cases, plus
idempotent re-runs.

Gamelists/scraped-media durability under ~/ES-DE is a related, noted gap
- not fixed here.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VLX1yYKJExGSXmgUhxKQG6
This commit is contained in:
Claude
2026-09-03 17:54:47 +00:00
parent 9ba1d7e9db
commit 4ed7a9d2d5
+113 -2
View File
@@ -325,6 +325,7 @@ EOF
echo " and Wii U (Cemu) in ES-DE via a second, opt-in 'Alternative emulators' command"
echo " - Expose Wolf's REST API socket to the host (WOLF_SOCKET_PATH + /var/run/wolf mount)"
echo " so './manage.sh controllers' can force distinct pad types per controller slot"
echo " - Force ES-DE's 'Run in background' off durably (mounts + writes esde-settings/es_settings.xml)"
return 0
fi
@@ -1391,6 +1392,49 @@ PS2XMLPY
log_success "PS2: added PCEE2 as the default RetroArch core (custom_systems/es_systems.xml) — ES-DE's"
log_info "own build doesn't ship it yet (added upstream in the not-yet-released 3.5.0)"
# ── ES-DE: force "Run in background" off ────────────────────────────────
# ES-DE's own compiled default for this IS already off (confirmed against
# its real Settings.cpp: mBoolMap["RunInBackground"] = {false, false}) —
# this write exists purely so that default stays durable and explicit
# rather than relying on it never having been toggled. Real, confirmed
# cause of a genuine bug otherwise: with it on, ES-DE keeps running and
# listening to every controller even after a game/emulator has launched
# and taken visual focus — a second controller's input can still reach
# ES-DE's own menu in the background and launch (and start playing audio
# for) a completely different game while the first one is still up
# front. ES-DE's own USERGUIDE.md explicitly names this failure mode
# ("make sure that the setting Run in background... is disabled").
# Confirmed live: this affects any system, not just Cemu.
#
# es_settings.xml is the user's OWN full settings state (theme, scraper
# prefs, everything) — unlike es_systems.xml this is never a full
# rewrite, only a surgical strip-and-reappend of this one <bool> entry,
# same idempotent pattern as everywhere else in this file. Written as a
# plain top-level element with no <settings> wrapper, matching what
# ES-DE's own Settings::saveFile() actually produces today (confirmed
# against its source — the "wrap everything in <settings>" format is
# loader-side forward-compatibility for a future ES-DE release, not
# what gets written now); either format loads fine either way.
mkdir -p "$GAME_STORAGE_DIR/esde-settings"
_ESDE_SETTINGS="$GAME_STORAGE_DIR/esde-settings/es_settings.xml"
backup_if_exists "$_ESDE_SETTINGS"
python3 - "$_ESDE_SETTINGS" << 'ESDESETTINGSPY'
import re, sys
path = sys.argv[1]
try:
with open(path) as f:
content = f.read()
except FileNotFoundError:
content = ''
content = re.sub(r'[ \t]*<bool name="RunInBackground" value="[^"]*"[ \t]*/>[ \t]*\n?', '', content)
line = ' <bool name="RunInBackground" value="false" />\n'
content = (content.rstrip('\n') + '\n' + line) if content.strip() else line
with open(path, 'w') as f:
f.write(content)
ESDESETTINGSPY
chown "$ACTUAL_USER:$ACTUAL_USER" "$_ESDE_SETTINGS"
log_success "ES-DE: 'Run in background (while game is launched)' forced off (esde-settings/es_settings.xml)"
# ── App selection ─────────────────────────────────────────────────────────
echo ""
echo "═══════════════════════════════════════════════════════"
@@ -1941,7 +1985,23 @@ CATALOG = {
f'{games}/retroarch:/home/retro/.config/retroarch:rw',
f'{games}/emulators:/mnt/games/emulators:rw',
f'{games}/emulators:/home/retro/Applications:rw',
f'{games}/esde-custom-systems:/home/retro/ES-DE/custom_systems:rw'],
f'{games}/esde-custom-systems:/home/retro/ES-DE/custom_systems:rw',
# ~/ES-DE (settings, gamelists, downloaded_media, logs) has
# NO mount at all otherwise (confirmed against ES-DE's own
# source and GOW's es-de startup.sh: getAppDataDirectory()
# is a plain $HOME/ES-DE, no XDG redirect) — Wolf normally
# reuses the same app container across sessions rather than
# recreating it each time (confirmed against Wolf's own
# docker.cpp: it only removes the container on session end
# if WOLF_STOP_CONTAINER_ON_EXIT=TRUE, which this repo never
# sets), so this doesn't get wiped every reconnect — but it
# IS lost on any real reinstall/container recreate, unlike
# everything else here which lives on the game drive. Only
# mounting settings/ specifically (not the whole ~/ES-DE
# tree) keeps this additive and non-breaking alongside the
# existing custom_systems mount above — gamelists/scraped
# media durability is a separate, not-yet-done improvement.
f'{games}/esde-settings:/home/retro/ES-DE/settings:rw'],
env=ESDE_ENV, cap_add=STD_CAP, security_opt=[], ipc_mode='host',
ulimits=[], privileged=False,
devices=['/dev/uinput:/dev/uinput'],
@@ -3670,7 +3730,23 @@ CATALOG = {
f'{games}/retroarch:/home/retro/.config/retroarch:rw',
f'{games}/emulators:/mnt/games/emulators:rw',
f'{games}/emulators:/home/retro/Applications:rw',
f'{games}/esde-custom-systems:/home/retro/ES-DE/custom_systems:rw'],
f'{games}/esde-custom-systems:/home/retro/ES-DE/custom_systems:rw',
# ~/ES-DE (settings, gamelists, downloaded_media, logs) has
# NO mount at all otherwise (confirmed against ES-DE's own
# source and GOW's es-de startup.sh: getAppDataDirectory()
# is a plain $HOME/ES-DE, no XDG redirect) — Wolf normally
# reuses the same app container across sessions rather than
# recreating it each time (confirmed against Wolf's own
# docker.cpp: it only removes the container on session end
# if WOLF_STOP_CONTAINER_ON_EXIT=TRUE, which this repo never
# sets), so this doesn't get wiped every reconnect — but it
# IS lost on any real reinstall/container recreate, unlike
# everything else here which lives on the game drive. Only
# mounting settings/ specifically (not the whole ~/ES-DE
# tree) keeps this additive and non-breaking alongside the
# existing custom_systems mount above — gamelists/scraped
# media durability is a separate, not-yet-done improvement.
f'{games}/esde-settings:/home/retro/ES-DE/settings:rw'],
env=ESDE_ENV, cap_add=STD_CAP, security_opt=[], ipc_mode='host',
ulimits=[], privileged=False,
devices=['/dev/uinput:/dev/uinput'],
@@ -4255,6 +4331,41 @@ regardless of which type it's sharing a GUID with. This is a reasoned
workaround, not one confirmed working live — if it doesn't pan out,
that's useful to know.
## ES-DE launches a second game while one is already running
**Symptom** (confirmed live, not Cemu-specific — happens on any system):
a second controller's input reaches ES-DE's own menu in the background
and launches an entirely different game — you'll hear/see it start
playing underneath whatever already has focus.
**Cause:** ES-DE's own **"Run in background (while game is launched)"**
setting. When it's on, ES-DE keeps running and listening to every
controller even after something else has launched and taken visual
focus — ES-DE's own USERGUIDE.md names this exact failure mode directly.
ES-DE's compiled default for this is already off, but nothing durably
enforced that in this setup before now, so it's easy for it to have
gotten toggled on at some point and stick that way.
**This installer now forces it off automatically** (\`esde-settings/es_settings.xml\`,
written fresh on every install/reinstall) — no menu digging required. If
you're on an install from before this existed, re-run \`sudo ./setup.sh wolf\`
to pick it up, or set it by hand: **Main Menu → Other Settings → Run in
background (while game is launched) → off**.
**Why this needed its own mount, not just a one-time write:** \`~/ES-DE\`
(settings, gamelists, scraped artwork, logs) had no bind mount onto the
game drive at all before this — confirmed against ES-DE's own source
(\`getAppDataDirectory()\` is a plain \`$HOME/ES-DE\`, no XDG redirect) and
GOW's own \`es-de\` startup script. In normal day-to-day use this mostly
didn't matter, since Wolf reuses the same app container across sessions
rather than recreating it each time (confirmed against Wolf's own
\`docker.cpp\`: the container is only removed on session end if
\`WOLF_STOP_CONTAINER_ON_EXIT=TRUE\`, which this repo never sets) — but it
meant this setting, and everything else under \`~/ES-DE\`, wasn't safe
across an actual reinstall or container recreate the way roms/saves/BIOS
already are. Only \`settings/\` is mounted now (\`esde-settings/\`, additive,
doesn't touch the existing \`custom_systems\` mount) — gamelists and
scraped media durability is a related gap, not yet fixed.
## EA games (Battlefront II 2017, etc.)
EA titles require GE-Proton and the EA App to be installed inside the Wine
prefix. The EA App handles authentication — without it, the game launches