From f04ecec2acd165e6dd5692fed21d0667bbf3ac52 Mon Sep 17 00:00:00 2001
From: Russell Sim <russell.sim@gmail.com>
Date: Sat, 13 Jun 2020 15:05:22 +0200
Subject: Proton directory discovery

Use search paths to find proton wine and the app directory, so that we can
support steam installations in multiple locations and 3rd party proton
installations.
---
 proto-wine/ftnoir_protocol_wine.cpp        |  8 ++--
 proto-wine/ftnoir_protocol_wine.h          |  5 ++-
 proto-wine/ftnoir_protocol_wine_dialog.cpp | 26 +++++++++---
 proto-wine/proton.cpp                      | 68 ++++++++++++++++++++----------
 4 files changed, 72 insertions(+), 35 deletions(-)

(limited to 'proto-wine')

diff --git a/proto-wine/ftnoir_protocol_wine.cpp b/proto-wine/ftnoir_protocol_wine.cpp
index aabaa30c..63308e9f 100644
--- a/proto-wine/ftnoir_protocol_wine.cpp
+++ b/proto-wine/ftnoir_protocol_wine.cpp
@@ -70,11 +70,11 @@ module_status wine::initialize()
         if (s.proton_appid == 0)
             return error(tr("Must specify application id for Proton (Steam Play)"));
 
-        QProcessEnvironment make_steam_environ(const QString& proton_version, int appid);
-        QString proton_path(const QString& proton_version);
+        QProcessEnvironment make_steam_environ(const QString& proton_path, int appid);
+        QString proton_path(const QString& proton_path);
 
-        wine_path = proton_path(s.proton_version);
-        env = make_steam_environ(s.proton_version, s.proton_appid);
+        wine_path = proton_path(s.proton_path().toString());
+        env = make_steam_environ(s.proton_path().toString(), s.proton_appid);
     }
     else
     {
diff --git a/proto-wine/ftnoir_protocol_wine.h b/proto-wine/ftnoir_protocol_wine.h
index 0e48e5b5..fc537b60 100644
--- a/proto-wine/ftnoir_protocol_wine.h
+++ b/proto-wine/ftnoir_protocol_wine.h
@@ -12,6 +12,7 @@ using namespace options;
 #include <QString>
 #include <QProcess>
 #include <QMutex>
+#include <QtCore/QVariant>
 
 #include <QDebug>
 
@@ -24,8 +25,8 @@ struct settings : opts
                 esync{b, "esync", true};
 
     value<int>     proton_appid{b, "proton-appid", 0};
-    value<QString> proton_version{b, "proton-version", {} },
-                   wineprefix{b, "wineprefix", "~/.wine"};
+    value<QVariant> proton_path{b, "proton-version", {} };
+    value<QString> wineprefix{b, "wineprefix", "~/.wine"};
     value<int>     protocol{b, "protocol", 2};
 };
 
diff --git a/proto-wine/ftnoir_protocol_wine_dialog.cpp b/proto-wine/ftnoir_protocol_wine_dialog.cpp
index b590ee94..76ccfdb5 100644
--- a/proto-wine/ftnoir_protocol_wine_dialog.cpp
+++ b/proto-wine/ftnoir_protocol_wine_dialog.cpp
@@ -1,19 +1,32 @@
 #include "ftnoir_protocol_wine.h"
 #include <QDebug>
+#include <QDir>
+
 #include "api/plugin-api.hpp"
 
-static const char* proton_versions[] = {
-    "5.0", "4.11", "4.2", "3.16", "3.7",
+static const char* proton_paths[] = {
+    "/.steam/steam/steamapps/common",
+    "/.steam/root/compatibilitytools.d",
+    "/.local/share/Steam/steamapps/common",
 };
 
+static const QStringList proton_filter = { "Proton*" };
+
 FTControls::FTControls()
 {
     ui.setupUi(this);
 
-    for (const char* version : proton_versions)
-        ui.proton_version->addItem(version, QVariant{version});
-
-    tie_setting(s.proton_version, ui.proton_version);
+    for (const char* path : proton_paths) {
+        QDir dir(QDir::homePath() + path);
+        dir.setFilter(QDir::Dirs);
+        dir.setNameFilters(proton_filter);
+        QFileInfoList list = dir.entryInfoList();
+        for (int i = 0; i < list.size(); ++i) {
+            QFileInfo fileInfo = list.at(i);
+            ui.proton_version->addItem(fileInfo.fileName(), QVariant{fileInfo.filePath()});
+        }
+    }
+    tie_setting(s.proton_path, ui.proton_version);
     tie_setting(s.variant_wine, ui.variant_wine);
     tie_setting(s.variant_proton, ui.variant_proton);
     tie_setting(s.esync, ui.esync);
@@ -37,4 +50,3 @@ void FTControls::doCancel()
     s.b->reload();
     close();
 }
-
diff --git a/proto-wine/proton.cpp b/proto-wine/proton.cpp
index 15306d26..e8d69fd9 100644
--- a/proto-wine/proton.cpp
+++ b/proto-wine/proton.cpp
@@ -7,55 +7,79 @@
 
 #ifndef OTR_WINE_NO_WRAPPER
 
+#include <QDebug>
 #include <QtGlobal>
 #include <QString>
 #include <QProcessEnvironment>
+#include <QDir>
+#include <QFileInfo>
 
-QProcessEnvironment make_steam_environ(const QString& proton_version, int appid)
+
+static const char* steam_paths[] = {
+    "/.steam/steam/steamapps/compatdata",
+    "/.local/share/Steam/steamapps/compatdata",
+};
+
+static const char* runtime_paths[] = {
+    "/.local/share/Steam/ubuntu12_32/steam-runtime",
+    "/.steam/ubuntu12_32/steam-runtime",
+};
+
+
+QProcessEnvironment make_steam_environ(const QString& proton_path, int appid)
 {
     auto ret = QProcessEnvironment::systemEnvironment();
     QString home = qgetenv("HOME");
+    QString runtime_path;
+
+    for (const char* path : runtime_paths) {
+        QDir dir(QDir::homePath() + path);
+        if (dir.exists())
+            runtime_path = dir.absolutePath();
+    }
 
     auto expand = [&](QString x) {
         x.replace("HOME", home);
-        x.replace("PROTON", proton_version);
+        x.replace("PROTON_PATH", proton_path);
+        x.replace("RUNTIME_PATH", runtime_path);
         return x;
     };
 
     QString path = expand(
-        ":HOME/.local/share/Steam/steamapps/common/Proton PROTON/dist/bin"
-        ":HOME/.local/share/Steam/ubuntu12_32/steam-runtime/amd64/bin"
-        ":HOME/.local/share/Steam/ubuntu12_32/steam-runtime/amd64/usr/bin"
+        ":PROTON_PATH/dist/bin"
     );
     path += ':'; path += qgetenv("PATH");
     ret.insert("PATH", path);
 
     QString library_path = expand(
-        ":HOME/.local/share/Steam/steamapps/common/Proton PROTON/dist/lib"
-        ":HOME/.local/share/Steam/steamapps/common/Proton PROTON/dist/lib64"
-        ":HOME/.local/share/Steam/ubuntu12_32/steam-runtime/pinned_libs_32"
-        ":HOME/.local/share/Steam/ubuntu12_32/steam-runtime/pinned_libs_64"
-        ":HOME/.local/share/Steam/ubuntu12_32/steam-runtime/i386/lib/i386-linux-gnu"
-        ":HOME/.local/share/Steam/ubuntu12_32/steam-runtime/i386/lib"
-        ":HOME/.local/share/Steam/ubuntu12_32/steam-runtime/i386/usr/lib/i386-linux-gnu"
-        ":HOME/.local/share/Steam/ubuntu12_32/steam-runtime/i386/usr/lib"
-        ":HOME/.local/share/Steam/ubuntu12_32/steam-runtime/amd64/lib/x86_64-linux-gnu"
-        ":HOME/.local/share/Steam/ubuntu12_32/steam-runtime/amd64/lib"
-        ":HOME/.local/share/Steam/ubuntu12_32/steam-runtime/amd64/usr/lib/x86_64-linux-gnu"
-        ":HOME/.local/share/Steam/ubuntu12_32/steam-runtime/amd64/usr/lib"
+        ":PROTON_PATH/dist/lib"
+        ":PROTON_PATH/dist/lib64"
+        ":RUNTIME_PATH/pinned_libs_32"
+        ":RUNTIME_PATH/pinned_libs_64"
+        ":RUNTIME_PATH/i386/lib/i386-linux-gnu"
+        ":RUNTIME_PATH/i386/lib"
+        ":RUNTIME_PATH/i386/usr/lib/i386-linux-gnu"
+        ":RUNTIME_PATH/i386/usr/lib"
+        ":RUNTIME_PATH/amd64/lib/x86_64-linux-gnu"
+        ":RUNTIME_PATH/amd64/lib"
+        ":RUNTIME_PATH/amd64/usr/lib/x86_64-linux-gnu"
+        ":RUNTIME_PATH/amd64/usr/lib"
     );
     library_path += ':'; library_path += qgetenv("LD_LIBRARY_PATH");
     ret.insert("LD_LIBRARY_PATH", library_path);
-    ret.insert("WINEPREFIX", expand("HOME/.local/share/Steam/steamapps/compatdata/%1/pfx").arg(appid));
+
+    for (const char* path : steam_paths) {
+        QDir dir(QDir::homePath() + path + expand("/%1/pfx").arg(appid));
+        if (dir.exists())
+            ret.insert("WINEPREFIX", dir.absolutePath());
+    }
 
     return ret;
 }
 
-QString proton_path(const QString& proton_version)
+QString proton_path(const QString& proton_path)
 {
-    QString wine_path = "HOME/.local/share/Steam/steamapps/common/Proton PROTON/dist/bin/wine";
-    wine_path.replace("HOME", qgetenv("HOME"));
-    wine_path.replace("PROTON", proton_version);
+    QString wine_path = proton_path + "/dist/bin/wine";
     return wine_path;
 }
 
-- 
cgit v1.2.3