diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-04-26 15:45:45 -0500 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-04-26 15:45:45 -0500 |
| commit | 3a148058861099499268722d4558c0963d76af19 (patch) | |
| tree | f3b1c29de68d4683528eaad17a57244df0309c9e | |
| parent | 5bc0bc642d9aabc8a2e9490424212b7e330514c4 (diff) | |
Per-instance Steam overlay toggle
New "Enable Steam Overlay" checkbox in Instance Manager (off by
default, key fluorine/steam_overlay). When enabled and the executable
has a Steam App ID, ProtonLauncher now:
- LD_PRELOADs gameoverlayrenderer.so (32+64 bit) from the running
Steam install for legacy GL/X11 hooks,
- sets SteamOverlayGameId so Steam's IPC handshake matches the app,
- exports ENABLE_VK_LAYER_VALVE_steam_overlay_1=1 and clears the
DISABLE_... counterpart so the Steam Vulkan implicit layer loads
even under pressure-vessel (this is what makes overlay work for
DXVK-rendered Bethesda games — most "manual" overlay setups skip
this and only get the GL hook),
- ensures Steam is running, and
- exposes <steam>/ubuntu12_{32,64} as SLR --filesystem= mounts so
the .so paths resolve inside the container.
No reaper wrapper, so Steam's "in-game" indicator may stay blank, but
the overlay itself attaches because the .so/Vulkan-layer hook the
process directly. Requires the user to actually own the game on the
running Steam account.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| -rw-r--r-- | src/src/instancemanagerdialog.cpp | 16 | ||||
| -rw-r--r-- | src/src/instancemanagerdialog.ui | 10 | ||||
| -rw-r--r-- | src/src/protonlauncher.cpp | 74 | ||||
| -rw-r--r-- | src/src/protonlauncher.h | 2 | ||||
| -rw-r--r-- | src/src/spawn.cpp | 9 |
5 files changed, 107 insertions, 4 deletions
diff --git a/src/src/instancemanagerdialog.cpp b/src/src/instancemanagerdialog.cpp index 46966c5..96511cc 100644 --- a/src/src/instancemanagerdialog.cpp +++ b/src/src/instancemanagerdialog.cpp @@ -252,6 +252,15 @@ InstanceManagerDialog::InstanceManagerDialog(PluginContainer& pc, QWidget* paren s.setValue("fluorine/vfs_root_builder", checked);
});
+ connect(ui->steamOverlayCheckBox, &QCheckBox::toggled, [&](bool checked) {
+ const auto* inst = singleSelection();
+ if (!inst) return;
+ const QString ini = inst->iniPath();
+ if (ini.isEmpty()) return;
+ QSettings s(ini, QSettings::IniFormat);
+ s.setValue("fluorine/steam_overlay", checked);
+ });
+
connect(ui->switchToInstance, &QPushButton::clicked, [&] {
openSelectedInstance();
});
@@ -829,6 +838,10 @@ void InstanceManagerDialog::fillData(const Instance& ii) ui->vfsRootBuilderCheckBox->blockSignals(true);
ui->vfsRootBuilderCheckBox->setChecked(s.value("fluorine/vfs_root_builder", true).toBool());
ui->vfsRootBuilderCheckBox->blockSignals(false);
+
+ ui->steamOverlayCheckBox->blockSignals(true);
+ ui->steamOverlayCheckBox->setChecked(s.value("fluorine/steam_overlay", false).toBool());
+ ui->steamOverlayCheckBox->blockSignals(false);
} else {
ui->prefixPath->clear();
ui->protonVersion->clear();
@@ -841,6 +854,9 @@ void InstanceManagerDialog::fillData(const Instance& ii) ui->vfsRootBuilderCheckBox->blockSignals(true);
ui->vfsRootBuilderCheckBox->setChecked(false);
ui->vfsRootBuilderCheckBox->blockSignals(false);
+ ui->steamOverlayCheckBox->blockSignals(true);
+ ui->steamOverlayCheckBox->setChecked(false);
+ ui->steamOverlayCheckBox->blockSignals(false);
}
}
diff --git a/src/src/instancemanagerdialog.ui b/src/src/instancemanagerdialog.ui index 6ec5455..2bf1d0a 100644 --- a/src/src/instancemanagerdialog.ui +++ b/src/src/instancemanagerdialog.ui @@ -350,6 +350,16 @@ </property> </widget> </item> + <item row="13" column="0" colspan="2"> + <widget class="QCheckBox" name="steamOverlayCheckBox"> + <property name="text"> + <string>Enable Steam Overlay</string> + </property> + <property name="toolTip"> + <string>Inject the Steam overlay (Shift+Tab) into the game. Requires Steam running, the game's Steam App ID set, and that you own the game on Steam. Combines LD_PRELOAD of gameoverlayrenderer.so with the Steam Vulkan overlay layer (needed for DXVK-rendered games like Skyrim/Fallout).</string> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/src/src/protonlauncher.cpp b/src/src/protonlauncher.cpp index d247965..8aecd47 100644 --- a/src/src/protonlauncher.cpp +++ b/src/src/protonlauncher.cpp @@ -409,6 +409,12 @@ ProtonLauncher& ProtonLauncher::setSteamDrm(bool useSteamDrm) return *this; } +ProtonLauncher& ProtonLauncher::setSteamOverlay(bool useSteamOverlay) +{ + m_useSteamOverlay = useSteamOverlay; + return *this; +} + ProtonLauncher& ProtonLauncher::setUseSLR(bool useSLR) { m_useSLR = useSLR; @@ -484,7 +490,7 @@ bool ProtonLauncher::launchWithProton(qint64& pid) const return false; } - if (m_useSteamDrm) { + if (m_useSteamDrm || m_useSteamOverlay) { ensureSteamRunning(); } @@ -530,6 +536,18 @@ bool ProtonLauncher::launchWithProton(qint64& pid) const slrArgs << QStringLiteral("--filesystem=%1").arg(protonDir); } + // Steam overlay needs gameoverlayrenderer.so visible inside the + // pressure-vessel container. Steam dirs are usually mapped already, + // but bind them explicitly to be safe — pressure-vessel's defaults + // change between SLR versions. + if (m_useSteamOverlay) { + const QString steamPath = detectSteamPath(); + if (!steamPath.isEmpty()) { + slrArgs << QStringLiteral("--filesystem=%1/ubuntu12_32").arg(steamPath) + << QStringLiteral("--filesystem=%1/ubuntu12_64").arg(steamPath); + } + } + // Expose dedicated xrandr dir so container sees our injected xrandr // (steamrt4 ships without it, required by Proton-GE protonfixes). // Pressure-vessel forces PATH=/usr/bin:/bin inside the container and @@ -592,6 +610,60 @@ bool ProtonLauncher::launchWithProton(qint64& pid) const env.insert("SteamGameId", appId); } + // Steam overlay injection. Requires (a) Steam client running (handled + // above), (b) the game owned on the running Steam account, (c) the env + // triplet SteamAppId/SteamGameId/SteamOverlayGameId pointing at the real + // Steam app id so the overlay's IPC handshake matches an installed app, + // (d) gameoverlayrenderer.so preloaded for legacy GL/X11 hooks, and (e) + // the Steam Vulkan overlay layer enabled for DXVK-rendered games (most + // modern titles via Proton — Bethesda games included). We don't add any + // wrapper process (no reaper) so Steam's "in-game" indicator may stay + // blank, but the overlay itself still attaches because the .so/layer + // hook the running process directly. + if (m_useSteamOverlay && m_steamAppId != 0 && !steamPath.isEmpty()) { + const QString appId = QString::number(m_steamAppId); + env.insert("SteamOverlayGameId", appId); + + const QString preload32 = + steamPath + "/ubuntu12_32/gameoverlayrenderer.so"; + const QString preload64 = + steamPath + "/ubuntu12_64/gameoverlayrenderer.so"; + + QStringList preloads; + if (QFileInfo::exists(preload32)) preloads << preload32; + if (QFileInfo::exists(preload64)) preloads << preload64; + + if (preloads.isEmpty()) { + MOBase::log::warn( + "Steam overlay enabled but gameoverlayrenderer.so not found under " + "'{}/ubuntu12_{{32,64}}' — skipping overlay env", + steamPath); + } else { + const QString existing = env.value("LD_PRELOAD"); + const QString joined = preloads.join(":"); + env.insert("LD_PRELOAD", + existing.isEmpty() ? joined : existing + ":" + joined); + + // Force-enable the Vulkan overlay implicit layer. Steam ships + // VkLayer_VALVE_steam_overlay as an *implicit* Vulkan layer that is + // normally auto-loaded for Steam-launched processes; pressure-vessel + // and some loader configurations skip it unless explicitly enabled. + env.insert("ENABLE_VK_LAYER_VALVE_steam_overlay_1", "1"); + // Also clear the disable-flag in case a Proton wrapper script set it. + env.remove("DISABLE_VK_LAYER_VALVE_steam_overlay_1"); + + MOBase::log::info( + "Steam overlay enabled (appid={}, LD_PRELOAD+={}, " + "ENABLE_VK_LAYER_VALVE_steam_overlay_1=1)", + appId, joined); + } + } else if (m_useSteamOverlay && m_steamAppId == 0) { + MOBase::log::warn( + "Steam overlay requested but no Steam App ID is set for this " + "executable — overlay needs an appid for Steam to recognise the " + "game; skipping"); + } + // When Steam DRM is disabled (e.g. GOG games), set UMU_ID so that // Proton-GE skips the built-in steam.exe bridge. Without this, Proton // tries to initialise the Steam client which causes an assertion failure diff --git a/src/src/protonlauncher.h b/src/src/protonlauncher.h index c9b5de8..9026921 100644 --- a/src/src/protonlauncher.h +++ b/src/src/protonlauncher.h @@ -21,6 +21,7 @@ public: ProtonLauncher& setSteamAppId(uint32_t id); ProtonLauncher& setWrapper(const QString& wrapperCmd); ProtonLauncher& setSteamDrm(bool useSteamDrm); + ProtonLauncher& setSteamOverlay(bool useSteamOverlay); ProtonLauncher& setUseSLR(bool useSLR); ProtonLauncher& setStoreVariant(const QString& variant); ProtonLauncher& addEnvVar(const QString& key, const QString& value); @@ -54,6 +55,7 @@ private: uint32_t m_steamAppId; QStringList m_wrapperCommands; bool m_useSteamDrm; + bool m_useSteamOverlay = false; bool m_useSLR = true; QString m_storeVariant; // "GOG", "Epic", or empty for Steam QMap<QString, QString> m_envVars; diff --git a/src/src/spawn.cpp b/src/src/spawn.cpp index 756b075..0d41401 100644 --- a/src/src/spawn.cpp +++ b/src/src/spawn.cpp @@ -805,16 +805,19 @@ int spawn(const SpawnParameters &sp, pid_t &processId) { const Settings *instanceForLaunch = Settings::maybeInstance();
bool useSteamDrm = true; // default
bool useSLR = true; // default on
+ bool useSteamOverlay = false; // default off
QString storeVariant;
if (instanceForLaunch) {
const QSettings instanceIni(instanceForLaunch->filename(),
QSettings::IniFormat);
- useSteamDrm = instanceIni.value("fluorine/steam_drm", true).toBool();
- useSLR = instanceIni.value("fluorine/use_slr", true).toBool();
- storeVariant = instanceIni.value("game_edition").toString().trimmed();
+ useSteamDrm = instanceIni.value("fluorine/steam_drm", true).toBool();
+ useSLR = instanceIni.value("fluorine/use_slr", true).toBool();
+ useSteamOverlay = instanceIni.value("fluorine/steam_overlay", false).toBool();
+ storeVariant = instanceIni.value("game_edition").toString().trimmed();
}
launcher.setSteamDrm(useSteamDrm)
+ .setSteamOverlay(useSteamOverlay)
.setStoreVariant(storeVariant)
.setUseSLR(useSLR);
|
