aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSulfurNitride <SulfurNitride@users.noreply.github.com>2026-05-30 13:15:32 -0500
committerSulfurNitride <SulfurNitride@users.noreply.github.com>2026-05-30 13:15:32 -0500
commit5c4603f12a727625ece236fc43846330fad3b9f2 (patch)
treeaee55f5f15d77d5860a3bfa7d197b6ae0cb78a66 /src
parent2464c836085cab832089b0f58c4bd74dfb679603 (diff)
Detect Steam Protons across libraries
Diffstat (limited to 'src')
-rw-r--r--src/src/steamdetection.cpp64
-rw-r--r--src/src/steamdetection.h3
-rw-r--r--src/src/vdfparser.cpp10
3 files changed, 62 insertions, 15 deletions
diff --git a/src/src/steamdetection.cpp b/src/src/steamdetection.cpp
index 7710edd..512b1fa 100644
--- a/src/src/steamdetection.cpp
+++ b/src/src/steamdetection.cpp
@@ -2,10 +2,13 @@
#include <QDir>
#include <QDirIterator>
+#include <QFile>
#include <QFileInfo>
#include <QStandardPaths>
#include <uibase/log.h>
+#include "vdfparser.h"
+
// ============================================================================
// SteamProtonInfo
// ============================================================================
@@ -56,6 +59,40 @@ QString findSteamPath()
return {};
}
+QStringList findSteamLibraryPaths()
+{
+ QStringList libraries;
+
+ const QString steamPath = findSteamPath();
+ if (steamPath.isEmpty())
+ return libraries;
+
+ auto addLibrary = [&](const QString& path) {
+ const QString cleanPath = QDir::cleanPath(path);
+ if (cleanPath.isEmpty() || libraries.contains(cleanPath))
+ return;
+ if (QFileInfo::exists(QDir(cleanPath).filePath(QStringLiteral("steamapps"))))
+ libraries.append(cleanPath);
+ };
+
+ addLibrary(steamPath);
+
+ QFile libraryFolders(QDir(steamPath).filePath(
+ QStringLiteral("steamapps/libraryfolders.vdf")));
+ if (!libraryFolders.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ MOBase::log::debug("Steam libraryfolders.vdf not found at '{}'",
+ libraryFolders.fileName());
+ return libraries;
+ }
+
+ const QString content = QString::fromUtf8(libraryFolders.readAll());
+ for (const QString& path : parseLibraryFolders(content)) {
+ addLibrary(path);
+ }
+
+ return libraries;
+}
+
// ============================================================================
// Proton Detection
// ============================================================================
@@ -143,27 +180,28 @@ QVector<SteamProtonInfo> findSteamProtons()
{
QVector<SteamProtonInfo> protons;
- const QString steamPath = findSteamPath();
- if (steamPath.isEmpty())
+ const QStringList steamLibraries = findSteamLibraryPaths();
+ if (steamLibraries.isEmpty())
return protons;
- // 1. Steam's built-in Protons (only entries starting with "Proton").
- {
+ // 1. Steam's built-in Protons across every Steam library. Steam may install
+ // tools like "Proton 10.0" under a secondary library's steamapps/common.
+ for (const QString& library : steamLibraries) {
QVector<SteamProtonInfo> builtin;
- scanProtonDir(steamPath + "/steamapps/common", true, builtin);
- // Keep only entries whose folder name starts with "Proton". Proton 11
- // had ntsync/futex deadlocks during wineboot -u on modern kernels; the
- // workaround now lives in prefixsetuprunner (waitforexitandrun + ntsync
- // env nudge) so we no longer blacklist it here.
+ scanProtonDir(QDir(library).filePath(QStringLiteral("steamapps/common")), true,
+ builtin);
for (auto& p : builtin) {
- if (!p.name.startsWith(QStringLiteral("Proton")))
- continue;
- protons.append(std::move(p));
+ if (p.name.startsWith(QStringLiteral("Proton"))) {
+ protons.append(std::move(p));
+ }
}
}
// 2. Custom Protons in user's compatibilitytools.d.
- scanProtonDir(steamPath + "/compatibilitytools.d", false, protons);
+ for (const QString& library : steamLibraries) {
+ scanProtonDir(QDir(library).filePath(QStringLiteral("compatibilitytools.d")),
+ false, protons);
+ }
// 3. System-level Protons.
scanProtonDir(QStringLiteral("/usr/share/steam/compatibilitytools.d"), false, protons);
diff --git a/src/src/steamdetection.h b/src/src/steamdetection.h
index fd8dc3f..4e0368f 100644
--- a/src/src/steamdetection.h
+++ b/src/src/steamdetection.h
@@ -26,6 +26,9 @@ struct SteamProtonInfo {
/// Find the Steam installation path (returns empty string if not found).
__attribute__((visibility("default"))) QString findSteamPath();
+/// Find all Steam library root paths, including secondary libraries.
+__attribute__((visibility("default"))) QStringList findSteamLibraryPaths();
+
/// Find all installed Proton versions (Proton 10+ only, sorted newest first).
__attribute__((visibility("default"))) QVector<SteamProtonInfo> findSteamProtons();
diff --git a/src/src/vdfparser.cpp b/src/src/vdfparser.cpp
index 1df8fe6..126be63 100644
--- a/src/src/vdfparser.cpp
+++ b/src/src/vdfparser.cpp
@@ -138,8 +138,14 @@ QStringList parseLibraryFolders(const QString& content)
return paths;
for (const VdfValue& entry : folders->asObject()) {
- const QString path = entry.getString(QStringLiteral("path"));
- if (!path.isEmpty())
+ QString path;
+ if (entry.isString()) {
+ path = entry.asString();
+ } else {
+ path = entry.getString(QStringLiteral("path"));
+ }
+
+ if (!path.isEmpty() && !paths.contains(path))
paths.append(path);
}
return paths;