aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSulfurNitride <SulfurNitride@users.noreply.github.com>2026-04-26 15:45:45 -0500
committerSulfurNitride <SulfurNitride@users.noreply.github.com>2026-04-26 15:45:45 -0500
commit3a148058861099499268722d4558c0963d76af19 (patch)
treef3b1c29de68d4683528eaad17a57244df0309c9e /src
parent5bc0bc642d9aabc8a2e9490424212b7e330514c4 (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>
Diffstat (limited to 'src')
-rw-r--r--src/src/instancemanagerdialog.cpp16
-rw-r--r--src/src/instancemanagerdialog.ui10
-rw-r--r--src/src/protonlauncher.cpp74
-rw-r--r--src/src/protonlauncher.h2
-rw-r--r--src/src/spawn.cpp9
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);