diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/src/mainwindow.cpp | 101 | ||||
| -rw-r--r-- | src/src/mainwindow.h | 5 | ||||
| -rw-r--r-- | src/src/organizercore.cpp | 29 | ||||
| -rw-r--r-- | src/src/organizercore.h | 2 | ||||
| -rw-r--r-- | src/src/settingsdialog.cpp | 14 | ||||
| -rw-r--r-- | src/src/settingsdialog.h | 5 |
6 files changed, 121 insertions, 35 deletions
diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index a928c6d..392c751 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -39,6 +39,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "executableslist.h" #include "filedialogmemory.h" #include "filterlist.h" +#include "fluorineupdater.h" #include "guessedvalue.h" #include "imodinterface.h" #include "installationmanager.h" @@ -496,6 +497,17 @@ MainWindow::MainWindow(Settings& settings, OrganizerCore& organizerCore, } }); + // Fluorine self-updater is constructed during setUserInterface() above + // (lazily by checkForFluorineUpdates()). The bare MO2 self-updater is + // no-op'd, so this is what actually drives the statusbar update badge. + if (auto* fu = m_OrganizerCore.fluorineUpdater()) { + connect(fu, &FluorineUpdater::updateAvailable, this, + [this](const FluorineUpdater::ReleaseInfo&) { + m_FluorineUpdatePending = true; + updateAvailable(); + }); + } + connect(m_OrganizerCore.modList(), &ModList::showMessage, [=, this](auto&& message) { showMessage(message); }); @@ -2381,7 +2393,10 @@ void MainWindow::on_startButton_clicked() }); // Pre-check: if this executable uses Proton and the current instance has SLR - // enabled, download SLR before launching if it isn't installed yet. + // enabled, ensure SLR is installed (and up-to-date with the latest steamrt4 + // BUILD_ID) before launching. downloadSlr() short-circuits on BUILD_ID match + // so once SLR is current this is a single HTTP GET; no UI is shown unless + // the runtime actually needs (re)downloading. if (selectedExecutable->useProton()) { const auto* s = Settings::maybeInstance(); bool useSLR = true; @@ -2389,43 +2404,49 @@ void MainWindow::on_startButton_clicked() QSettings const instanceIni(s->filename(), QSettings::IniFormat); useSLR = instanceIni.value("fluorine/use_slr", true).toBool(); } - if (useSLR && !isSlrInstalled()) { - auto* progress = new QProgressDialog( - tr("Downloading Steam Linux Runtime (~200 MB)...\n" - "This is required to launch games. Check the MO2 log for details."), - tr("Cancel"), 0, 0, this); - progress->setWindowTitle(tr("Steam Linux Runtime")); - progress->setWindowModality(Qt::WindowModal); - progress->setAttribute(Qt::WA_ShowWithoutActivating); - progress->setMinimumDuration(0); + if (useSLR) { + const bool freshInstall = !isSlrInstalled(); + // Only show the heavyweight progress dialog on a fresh install. + // Up-to-date checks happen quietly in the background here so we don't + // block launch on a remote BUILD_ID fetch — the up-to-date case is + // handled at startup by OrganizerCore::checkForSlrUpdates(). + if (freshInstall) { + auto* progress = new QProgressDialog( + tr("Downloading Steam Linux Runtime (~200 MB)...\n" + "This is required to launch games. Check the MO2 log for details."), + tr("Cancel"), 0, 0, this); + progress->setWindowTitle(tr("Steam Linux Runtime")); + progress->setWindowModality(Qt::WindowModal); + progress->setAttribute(Qt::WA_ShowWithoutActivating); + progress->setMinimumDuration(0); - int cancelFlag = 0; - connect(progress, &QProgressDialog::canceled, this, [&cancelFlag] { - cancelFlag = 1; - }); + int cancelFlag = 0; + connect(progress, &QProgressDialog::canceled, this, [&cancelFlag] { + cancelFlag = 1; + }); - // Run download synchronously using an event loop so the dialog stays responsive. - QFutureWatcher<QString> watcher; - QEventLoop loop; - connect(&watcher, &QFutureWatcher<QString>::finished, &loop, &QEventLoop::quit); - watcher.setFuture(QtConcurrent::run([&cancelFlag]() -> QString { - return downloadSlr(nullptr, nullptr, &cancelFlag); - })); - progress->show(); - loop.exec(); - progress->close(); - progress->deleteLater(); + QFutureWatcher<QString> watcher; + QEventLoop loop; + connect(&watcher, &QFutureWatcher<QString>::finished, &loop, &QEventLoop::quit); + watcher.setFuture(QtConcurrent::run([&cancelFlag]() -> QString { + return downloadSlr(nullptr, nullptr, &cancelFlag); + })); + progress->show(); + loop.exec(); + progress->close(); + progress->deleteLater(); - const QString err = watcher.result(); - if (cancelFlag) { - return; // user cancelled, don't launch - } - if (!err.isEmpty()) { - log::error("[SLR] Download failed: {}", err); - QMessageBox::warning(this, tr("Steam Linux Runtime"), - tr("Steam Linux Runtime download failed:\n%1\n\n" - "You can disable SLR in the Instance Manager and try again.").arg(err)); - return; + const QString err = watcher.result(); + if (cancelFlag) { + return; // user cancelled, don't launch + } + if (!err.isEmpty()) { + log::error("[SLR] Download failed: {}", err); + QMessageBox::warning(this, tr("Steam Linux Runtime"), + tr("Steam Linux Runtime download failed:\n%1\n\n" + "You can disable SLR in the Instance Manager and try again.").arg(err)); + return; + } } } } @@ -3144,6 +3165,16 @@ void MainWindow::motdReceived(const QString& motd) void MainWindow::on_actionUpdate_triggered() { + // Fluorine has its own updater (Settings → Updates). The MO2 self-updater + // is no-op'd (see SelfUpdater::testForUpdate). Open the Updates tab so + // the user can see the release info and trigger Install & restart. + if (m_FluorineUpdatePending) { + Settings& settings = m_OrganizerCore.settings(); + SettingsDialog dialog(&m_PluginContainer, settings, this); + dialog.selectTabByLabel(tr("Updates")); + dialog.exec(); + return; + } m_OrganizerCore.startMOUpdate(); } diff --git a/src/src/mainwindow.h b/src/src/mainwindow.h index 20a7286..9af07bd 100644 --- a/src/src/mainwindow.h +++ b/src/src/mainwindow.h @@ -293,6 +293,11 @@ private: QTime m_StartTime;
+ // Set when FluorineUpdater reports a new release; consumed by
+ // on_actionUpdate_triggered() to route to Settings → Updates instead of
+ // the (no-op'd) MO2 self-updater.
+ bool m_FluorineUpdatePending = false;
+
OrganizerCore& m_OrganizerCore;
PluginContainer& m_PluginContainer;
diff --git a/src/src/organizercore.cpp b/src/src/organizercore.cpp index 8b3171e..3707d58 100644 --- a/src/src/organizercore.cpp +++ b/src/src/organizercore.cpp @@ -2,6 +2,7 @@ #include "categoriesdialog.h" #include "credentialsdialog.h" #include "fluorineupdater.h" +#include "slrmanager.h" #include "delayedfilewriter.h" #include "directoryrefresher.h" #include "env.h" @@ -48,6 +49,7 @@ #include <chrono> #include <cstdio> #include <filesystem> +#include <thread> #include <QApplication> #include <QCoreApplication> #include <QDialog> @@ -393,9 +395,36 @@ void OrganizerCore::checkForUpdates() if (m_UserInterface != nullptr) { m_Updater.testForUpdate(m_Settings); checkForFluorineUpdates(); + checkForSlrUpdates(); } } +void OrganizerCore::checkForSlrUpdates() +{ + // SLR auto-update: only relevant if SLR is already installed. The first- + // install case is handled at game launch in MainWindow, where the user gets + // a progress dialog. Here we silently background-fetch a newer steamrt4 + // image when one exists; downloadSlr() short-circuits on BUILD_ID match so + // the cost is one HTTP GET when already up-to-date. + if (!m_Settings.checkForUpdates()) { + return; + } + if (m_Settings.network().offlineMode()) { + return; + } + if (!isSlrInstalled()) { + return; + } + + // Fire and forget on a detached thread. No UI; result is logged. + std::thread([]() { + const QString err = downloadSlr(nullptr, nullptr, nullptr); + if (!err.isEmpty()) { + MOBase::log::warn("SLR update check failed: {}", err); + } + }).detach(); +} + void OrganizerCore::checkForFluorineUpdates() { // Set up the Fluorine self-update checker lazily so repeated calls don't diff --git a/src/src/organizercore.h b/src/src/organizercore.h index 7f60998..7ef7713 100644 --- a/src/src/organizercore.h +++ b/src/src/organizercore.h @@ -258,10 +258,12 @@ public: void checkForUpdates();
void checkForFluorineUpdates();
+ void checkForSlrUpdates();
void startMOUpdate();
Settings& settings();
SelfUpdater* updater() { return &m_Updater; }
+ class FluorineUpdater* fluorineUpdater() const { return m_FluorineUpdater; }
InstallationManager* installationManager();
MOShared::DirectoryEntry* directoryStructure() { return m_DirectoryStructure; }
DirectoryRefresher* directoryRefresher() { return m_DirectoryRefresher.get(); }
diff --git a/src/src/settingsdialog.cpp b/src/src/settingsdialog.cpp index c0e254b..e07ac71 100644 --- a/src/src/settingsdialog.cpp +++ b/src/src/settingsdialog.cpp @@ -82,11 +82,25 @@ ExitFlags SettingsDialog::exitNeeded() const return m_exit;
}
+void SettingsDialog::selectTabByLabel(const QString& label)
+{
+ for (int i = 0; i < ui->tabWidget->count(); ++i) {
+ if (ui->tabWidget->tabText(i) == label) {
+ ui->tabWidget->setCurrentIndex(i);
+ m_pendingTabOverride = i;
+ return;
+ }
+ }
+}
+
int SettingsDialog::exec()
{
GeometrySaver gs(m_settings, this);
m_settings.widgets().restoreIndex(ui->tabWidget);
+ if (m_pendingTabOverride >= 0) {
+ ui->tabWidget->setCurrentIndex(m_pendingTabOverride);
+ }
auto ret = TutorableDialog::exec();
diff --git a/src/src/settingsdialog.h b/src/src/settingsdialog.h index 864eae7..030f6f6 100644 --- a/src/src/settingsdialog.h +++ b/src/src/settingsdialog.h @@ -80,6 +80,10 @@ public: void setExitNeeded(ExitFlags e);
ExitFlags exitNeeded() const;
+ // Pre-select a tab by its visible label (e.g. "Updates"). Must be called
+ // before exec(); any saved tab index is overridden.
+ void selectTabByLabel(const QString& label);
+
int exec() override;
public slots:
@@ -91,6 +95,7 @@ private: std::vector<std::unique_ptr<SettingsTab>> m_tabs;
ExitFlags m_exit;
PluginContainer* m_pluginContainer;
+ int m_pendingTabOverride = -1;
};
#endif // SETTINGSDIALOG_H
|
