diff --git a/src/app.cpp b/src/app.cpp index fff446d..042d96b 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -12,14 +12,17 @@ #include "retroarchimporter.h" #include "steamimporter.h" +#include #include #include #include #include #include #include +#include #include #include +#include #include App *App::s_instance = nullptr; @@ -34,6 +37,12 @@ App::App(QObject *parent) , m_mediaManager(new MediaManager(this)) , m_config(new Config(this)) { + if (QCoreApplication::instance()) { + connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, [this]() { + m_shuttingDown.store(true); + }); + } + loadLibrary(); if (!m_config->importSteam()) { @@ -147,6 +156,11 @@ App::App(QObject *parent) }); } +App::~App() +{ + m_shuttingDown.store(true); +} + App *App::instance() { if (!s_instance) { @@ -225,7 +239,7 @@ void App::setImportStatus(const QString &status) void App::importAllGames() { - if (m_importing) + if (m_importing || m_shuttingDown.load()) return; const bool anyEnabled = m_config->importSteam() || m_config->importLutris() || m_config->importHeroic() || m_config->importDesktop() @@ -256,335 +270,463 @@ void App::importAllGames() setImporting(true); setImportStatus(tr("Importing games...")); - [[maybe_unused]] auto future = QtConcurrent::run([this, doSteam, doLutris, doHeroic, doDesktop, doBottles, doFlatpak, doItch, doLegendary, doRetroArch]() { - int totalCount = 0; - - // Import from Steam - if (doSteam) { - QMetaObject::invokeMethod( - this, - [this]() { - setImportStatus(tr("Scanning Steam library...")); - }, - Qt::QueuedConnection); - - SteamImporter steamImporter; - QList steamGames = steamImporter.importGames(); - for (Game *game : steamGames) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + [[maybe_unused]] auto future = + QtConcurrent::run([self = QPointer(this), doSteam, doLutris, doHeroic, doDesktop, doBottles, doFlatpak, doItch, doLegendary, doRetroArch]() { + if (!self || self->m_shuttingDown.load()) { + return; } - QMetaObject::invokeMethod( - this, - [this, steamGames]() { - if (!m_config->importSteam()) { - for (Game *game : steamGames) { - if (game) { - game->deleteLater(); - } + QThread *appThread = self->thread(); + auto shouldAbort = [&self]() { + return !self || self->m_shuttingDown.load(); + }; + + int totalCount = 0; + + // Import from Steam + if (doSteam) { + QMetaObject::invokeMethod( + self.data(), + [self]() { + if (self && !self->m_shuttingDown.load()) { + self->setImportStatus(self->tr("Scanning Steam library...")); } - return; - } + }, + Qt::QueuedConnection); + + SteamImporter steamImporter; + QList steamGames = steamImporter.importGames(); + + if (shouldAbort()) { for (Game *game : steamGames) { - m_gameModel->addGame(game); + delete game; } - }, - Qt::QueuedConnection); - totalCount += steamGames.count(); - } + return; + } + for (Game *game : steamGames) { + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } + } - // Import from Lutris - if (doLutris) { - QMetaObject::invokeMethod( - this, - [this]() { - setImportStatus(tr("Scanning Lutris library...")); - }, - Qt::QueuedConnection); - - LutrisImporter lutrisImporter; - QList lutrisGames = lutrisImporter.importGames(); - for (Game *game : lutrisGames) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + QMetaObject::invokeMethod( + self.data(), + [self, steamGames]() { + if (!self || self->m_shuttingDown.load() || !self->m_config->importSteam()) { + for (Game *game : steamGames) { + if (game) { + game->deleteLater(); + } + } + return; + } + for (Game *game : steamGames) { + self->m_gameModel->addGame(game); + } + }, + Qt::QueuedConnection); + totalCount += steamGames.count(); } - QMetaObject::invokeMethod( - this, - [this, lutrisGames]() { - if (!m_config->importLutris()) { + // Import from Lutris + if (doLutris) { + QMetaObject::invokeMethod( + self.data(), + [self]() { + if (self && !self->m_shuttingDown.load()) { + self->setImportStatus(self->tr("Scanning Lutris library...")); + } + }, + Qt::QueuedConnection); + + LutrisImporter lutrisImporter; + QList lutrisGames = lutrisImporter.importGames(); + + if (shouldAbort()) { + for (Game *game : lutrisGames) { + delete game; + } + return; + } + for (Game *game : lutrisGames) { + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } + } + + QMetaObject::invokeMethod( + self.data(), + [self, lutrisGames]() { + if (!self || self->m_shuttingDown.load() || !self->m_config->importLutris()) { + for (Game *game : lutrisGames) { + if (game) { + game->deleteLater(); + } + } + return; + } for (Game *game : lutrisGames) { if (game) { - game->deleteLater(); + self->m_gameModel->addGame(game); } } - return; - } - for (Game *game : lutrisGames) { - m_gameModel->addGame(game); - } - }, - Qt::QueuedConnection); - totalCount += lutrisGames.count(); - } - - // Import from Heroic - if (doHeroic) { - QMetaObject::invokeMethod( - this, - [this]() { - setImportStatus(tr("Scanning Heroic library...")); - }, - Qt::QueuedConnection); - - HeroicImporter heroicImporter; - QList heroicGames = heroicImporter.importGames(); - for (Game *game : heroicGames) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + }, + Qt::QueuedConnection); + totalCount += lutrisGames.count(); } - QMetaObject::invokeMethod( - this, - [this, heroicGames]() { - if (!m_config->importHeroic()) { + // Import from Heroic + if (doHeroic) { + QMetaObject::invokeMethod( + self.data(), + [self]() { + if (self && !self->m_shuttingDown.load()) { + self->setImportStatus(self->tr("Scanning Heroic library...")); + } + }, + Qt::QueuedConnection); + + HeroicImporter heroicImporter; + QList heroicGames = heroicImporter.importGames(); + + if (shouldAbort()) { + for (Game *game : heroicGames) { + delete game; + } + return; + } + for (Game *game : heroicGames) { + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } + } + + QMetaObject::invokeMethod( + self.data(), + [self, heroicGames]() { + if (!self || self->m_shuttingDown.load() || !self->m_config->importHeroic()) { + for (Game *game : heroicGames) { + if (game) { + game->deleteLater(); + } + } + return; + } for (Game *game : heroicGames) { if (game) { - game->deleteLater(); + self->m_gameModel->addGame(game); } } - return; - } - for (Game *game : heroicGames) { - m_gameModel->addGame(game); - } - }, - Qt::QueuedConnection); - totalCount += heroicGames.count(); - } - - // Import from Desktop entries - if (doDesktop) { - QMetaObject::invokeMethod( - this, - [this]() { - setImportStatus(tr("Scanning desktop entries...")); - }, - Qt::QueuedConnection); - - DesktopImporter desktopImporter; - QList desktopGames = desktopImporter.importGames(); - for (Game *game : desktopGames) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + }, + Qt::QueuedConnection); + totalCount += heroicGames.count(); } - QMetaObject::invokeMethod( - this, - [this, desktopGames]() { - if (!m_config->importDesktop()) { + // Import from Desktop entries + if (doDesktop) { + QMetaObject::invokeMethod( + self.data(), + [self]() { + if (self && !self->m_shuttingDown.load()) { + self->setImportStatus(self->tr("Scanning desktop entries...")); + } + }, + Qt::QueuedConnection); + + DesktopImporter desktopImporter; + QList desktopGames = desktopImporter.importGames(); + + if (shouldAbort()) { + for (Game *game : desktopGames) { + delete game; + } + return; + } + for (Game *game : desktopGames) { + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } + } + + QMetaObject::invokeMethod( + self.data(), + [self, desktopGames]() { + if (!self || self->m_shuttingDown.load() || !self->m_config->importDesktop()) { + for (Game *game : desktopGames) { + if (game) { + game->deleteLater(); + } + } + return; + } for (Game *game : desktopGames) { if (game) { - game->deleteLater(); + self->m_gameModel->addGame(game); } } - return; - } - for (Game *game : desktopGames) { - m_gameModel->addGame(game); - } - }, - Qt::QueuedConnection); - totalCount += desktopGames.count(); - } - - // Import from Bottles - if (doBottles) { - QMetaObject::invokeMethod( - this, - [this]() { - setImportStatus(tr("Scanning Bottles...")); - }, - Qt::QueuedConnection); - - BottlesImporter bottlesImporter; - QList bottlesGames = bottlesImporter.importGames(); - for (Game *game : bottlesGames) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + }, + Qt::QueuedConnection); + totalCount += desktopGames.count(); } - QMetaObject::invokeMethod( - this, - [this, bottlesGames]() { - if (!m_config->importBottles()) { + // Import from Bottles + if (doBottles) { + QMetaObject::invokeMethod( + self.data(), + [self]() { + if (self && !self->m_shuttingDown.load()) { + self->setImportStatus(self->tr("Scanning Bottles...")); + } + }, + Qt::QueuedConnection); + + BottlesImporter bottlesImporter; + QList bottlesGames = bottlesImporter.importGames(); + + if (shouldAbort()) { + for (Game *game : bottlesGames) { + delete game; + } + return; + } + for (Game *game : bottlesGames) { + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } + } + + QMetaObject::invokeMethod( + self.data(), + [self, bottlesGames]() { + if (!self || self->m_shuttingDown.load() || !self->m_config->importBottles()) { + for (Game *game : bottlesGames) { + if (game) { + game->deleteLater(); + } + } + return; + } for (Game *game : bottlesGames) { if (game) { - game->deleteLater(); + self->m_gameModel->addGame(game); } } - return; - } - for (Game *game : bottlesGames) { - m_gameModel->addGame(game); - } - }, - Qt::QueuedConnection); - totalCount += bottlesGames.count(); - } - - // Import from Flatpak - if (doFlatpak) { - QMetaObject::invokeMethod( - this, - [this]() { - setImportStatus(tr("Scanning Flatpak games...")); - }, - Qt::QueuedConnection); - - FlatpakImporter flatpakImporter; - QList flatpakGames = flatpakImporter.importGames(); - for (Game *game : flatpakGames) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + }, + Qt::QueuedConnection); + totalCount += bottlesGames.count(); } - QMetaObject::invokeMethod( - this, - [this, flatpakGames]() { - if (!m_config->importFlatpak()) { + // Import from Flatpak + if (doFlatpak) { + QMetaObject::invokeMethod( + self.data(), + [self]() { + if (self && !self->m_shuttingDown.load()) { + self->setImportStatus(self->tr("Scanning Flatpak games...")); + } + }, + Qt::QueuedConnection); + + FlatpakImporter flatpakImporter; + QList flatpakGames = flatpakImporter.importGames(); + + if (shouldAbort()) { + for (Game *game : flatpakGames) { + delete game; + } + return; + } + for (Game *game : flatpakGames) { + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } + } + + QMetaObject::invokeMethod( + self.data(), + [self, flatpakGames]() { + if (!self || self->m_shuttingDown.load() || !self->m_config->importFlatpak()) { + for (Game *game : flatpakGames) { + if (game) { + game->deleteLater(); + } + } + return; + } for (Game *game : flatpakGames) { if (game) { - game->deleteLater(); + self->m_gameModel->addGame(game); } } - return; - } - for (Game *game : flatpakGames) { - m_gameModel->addGame(game); - } - }, - Qt::QueuedConnection); - totalCount += flatpakGames.count(); - } - - // Import from itch.io - if (doItch) { - QMetaObject::invokeMethod( - this, - [this]() { - setImportStatus(tr("Scanning itch.io library...")); - }, - Qt::QueuedConnection); - - ItchImporter itchImporter; - QList itchGames = itchImporter.importGames(); - for (Game *game : itchGames) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + }, + Qt::QueuedConnection); + totalCount += flatpakGames.count(); } - QMetaObject::invokeMethod( - this, - [this, itchGames]() { - if (!m_config->importItch()) { + // Import from itch.io + if (doItch) { + QMetaObject::invokeMethod( + self.data(), + [self]() { + if (self && !self->m_shuttingDown.load()) { + self->setImportStatus(self->tr("Scanning itch.io library...")); + } + }, + Qt::QueuedConnection); + + ItchImporter itchImporter; + QList itchGames = itchImporter.importGames(); + + if (shouldAbort()) { + for (Game *game : itchGames) { + delete game; + } + return; + } + for (Game *game : itchGames) { + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } + } + + QMetaObject::invokeMethod( + self.data(), + [self, itchGames]() { + if (!self || self->m_shuttingDown.load() || !self->m_config->importItch()) { + for (Game *game : itchGames) { + if (game) { + game->deleteLater(); + } + } + return; + } for (Game *game : itchGames) { if (game) { - game->deleteLater(); + self->m_gameModel->addGame(game); } } - return; - } - for (Game *game : itchGames) { - m_gameModel->addGame(game); - } - }, - Qt::QueuedConnection); - totalCount += itchGames.count(); - } - - // Import from Legendary - if (doLegendary) { - QMetaObject::invokeMethod( - this, - [this]() { - setImportStatus(tr("Scanning Legendary library...")); - }, - Qt::QueuedConnection); - - LegendaryImporter legendaryImporter; - QList legendaryGames = legendaryImporter.importGames(); - for (Game *game : legendaryGames) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + }, + Qt::QueuedConnection); + totalCount += itchGames.count(); } - QMetaObject::invokeMethod( - this, - [this, legendaryGames]() { - if (!m_config->importLegendary()) { + // Import from Legendary + if (doLegendary) { + QMetaObject::invokeMethod( + self.data(), + [self]() { + if (self && !self->m_shuttingDown.load()) { + self->setImportStatus(self->tr("Scanning Legendary library...")); + } + }, + Qt::QueuedConnection); + + LegendaryImporter legendaryImporter; + QList legendaryGames = legendaryImporter.importGames(); + + if (shouldAbort()) { + for (Game *game : legendaryGames) { + delete game; + } + return; + } + for (Game *game : legendaryGames) { + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } + } + + QMetaObject::invokeMethod( + self.data(), + [self, legendaryGames]() { + if (!self || self->m_shuttingDown.load() || !self->m_config->importLegendary()) { + for (Game *game : legendaryGames) { + if (game) { + game->deleteLater(); + } + } + return; + } for (Game *game : legendaryGames) { if (game) { - game->deleteLater(); + self->m_gameModel->addGame(game); } } - return; - } - for (Game *game : legendaryGames) { - m_gameModel->addGame(game); - } - }, - Qt::QueuedConnection); - totalCount += legendaryGames.count(); - } - - // Import from RetroArch - if (doRetroArch) { - QMetaObject::invokeMethod( - this, - [this]() { - setImportStatus(tr("Scanning RetroArch playlists...")); - }, - Qt::QueuedConnection); - - RetroArchImporter retroArchImporter; - QList retroArchGames = retroArchImporter.importGames(); - for (Game *game : retroArchGames) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + }, + Qt::QueuedConnection); + totalCount += legendaryGames.count(); } - QMetaObject::invokeMethod( - this, - [this, retroArchGames]() { - if (!m_config->importRetroArch()) { + // Import from RetroArch + if (doRetroArch) { + QMetaObject::invokeMethod( + self.data(), + [self]() { + if (self && !self->m_shuttingDown.load()) { + self->setImportStatus(self->tr("Scanning RetroArch playlists...")); + } + }, + Qt::QueuedConnection); + + RetroArchImporter retroArchImporter; + QList retroArchGames = retroArchImporter.importGames(); + + if (shouldAbort()) { + for (Game *game : retroArchGames) { + delete game; + } + return; + } + for (Game *game : retroArchGames) { + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } + } + + QMetaObject::invokeMethod( + self.data(), + [self, retroArchGames]() { + if (!self || self->m_shuttingDown.load() || !self->m_config->importRetroArch()) { + for (Game *game : retroArchGames) { + if (game) { + game->deleteLater(); + } + } + return; + } for (Game *game : retroArchGames) { if (game) { - game->deleteLater(); + self->m_gameModel->addGame(game); } } + }, + Qt::QueuedConnection); + totalCount += retroArchGames.count(); + } + + // Complete + QMetaObject::invokeMethod( + self.data(), + [self, totalCount]() { + if (!self || self->m_shuttingDown.load()) { return; } - for (Game *game : retroArchGames) { - m_gameModel->addGame(game); - } + self->setImportStatus(self->tr("Import complete: %1 games found").arg(totalCount)); + self->setImporting(false); + self->saveLibrary(); + Q_EMIT self->importCompleted(totalCount); }, Qt::QueuedConnection); - totalCount += retroArchGames.count(); - } - - // Complete - QMetaObject::invokeMethod( - this, - [this, totalCount]() { - setImportStatus(tr("Import complete: %1 games found").arg(totalCount)); - setImporting(false); - saveLibrary(); - Q_EMIT importCompleted(totalCount); - }, - Qt::QueuedConnection); - }); + }); } void App::importFromSteam() diff --git a/src/app.h b/src/app.h index 0214ec3..0c32f1e 100644 --- a/src/app.h +++ b/src/app.h @@ -3,6 +3,8 @@ #pragma once +#include + #include #include #include @@ -36,6 +38,8 @@ public: static App *instance(); static App *create(QQmlEngine *engine, QJSEngine *scriptEngine); + ~App() override; + GameModel *gameModel() const; GameLauncher *launcher() const; RunnerManagerClient *runnerManager() const; @@ -90,6 +94,8 @@ private: QString m_importStatus; QHash m_removedGames; + std::atomic_bool m_shuttingDown{false}; + void setImporting(bool importing); void setImportStatus(const QString &status); };