From cca49615d68bd8b07c554e4cc791b9e9aab81a1d Mon Sep 17 00:00:00 2001 From: Marco Allegretti Date: Fri, 13 Feb 2026 18:55:33 +0100 Subject: [PATCH] App: guard individual import tasks during shutdown --- src/app.cpp | 432 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 324 insertions(+), 108 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 042d96b..349bd68 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -731,31 +731,55 @@ void App::importAllGames() void App::importFromSteam() { - if (m_importing) + if (m_importing || m_shuttingDown.load()) return; setImporting(true); setImportStatus(tr("Scanning Steam library...")); - [[maybe_unused]] auto future = QtConcurrent::run([this]() { + [[maybe_unused]] auto future = QtConcurrent::run([self = QPointer(this)]() { + if (!self || self->m_shuttingDown.load()) { + return; + } + SteamImporter importer; QList games = importer.importGames(); + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + delete game; + } + return; + } + + QThread *appThread = self->thread(); for (Game *game : games) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } } QMetaObject::invokeMethod( - this, - [this, games]() { - for (Game *game : games) { - m_gameModel->addGame(game); + self.data(), + [self, games]() { + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + if (game) { + game->deleteLater(); + } + } + return; } - setImportStatus(tr("Steam import complete: %1 games found").arg(games.count())); - setImporting(false); - saveLibrary(); - Q_EMIT importCompleted(games.count()); + for (Game *game : games) { + if (game) { + self->m_gameModel->addGame(game); + } + } + self->setImportStatus(self->tr("Steam import complete: %1 games found").arg(games.count())); + self->setImporting(false); + self->saveLibrary(); + Q_EMIT self->importCompleted(games.count()); }, Qt::QueuedConnection); }); @@ -763,31 +787,55 @@ void App::importFromSteam() void App::importFromLutris() { - if (m_importing) + if (m_importing || m_shuttingDown.load()) return; setImporting(true); setImportStatus(tr("Scanning Lutris library...")); - [[maybe_unused]] auto future = QtConcurrent::run([this]() { + [[maybe_unused]] auto future = QtConcurrent::run([self = QPointer(this)]() { + if (!self || self->m_shuttingDown.load()) { + return; + } + LutrisImporter importer; QList games = importer.importGames(); + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + delete game; + } + return; + } + + QThread *appThread = self->thread(); for (Game *game : games) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } } QMetaObject::invokeMethod( - this, - [this, games]() { - for (Game *game : games) { - m_gameModel->addGame(game); + self.data(), + [self, games]() { + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + if (game) { + game->deleteLater(); + } + } + return; } - setImportStatus(tr("Lutris import complete: %1 games found").arg(games.count())); - setImporting(false); - saveLibrary(); - Q_EMIT importCompleted(games.count()); + for (Game *game : games) { + if (game) { + self->m_gameModel->addGame(game); + } + } + self->setImportStatus(self->tr("Lutris import complete: %1 games found").arg(games.count())); + self->setImporting(false); + self->saveLibrary(); + Q_EMIT self->importCompleted(games.count()); }, Qt::QueuedConnection); }); @@ -795,31 +843,55 @@ void App::importFromLutris() void App::importFromHeroic() { - if (m_importing) + if (m_importing || m_shuttingDown.load()) return; setImporting(true); setImportStatus(tr("Scanning Heroic library...")); - [[maybe_unused]] auto future = QtConcurrent::run([this]() { + [[maybe_unused]] auto future = QtConcurrent::run([self = QPointer(this)]() { + if (!self || self->m_shuttingDown.load()) { + return; + } + HeroicImporter importer; QList games = importer.importGames(); + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + delete game; + } + return; + } + + QThread *appThread = self->thread(); for (Game *game : games) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } } QMetaObject::invokeMethod( - this, - [this, games]() { - for (Game *game : games) { - m_gameModel->addGame(game); + self.data(), + [self, games]() { + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + if (game) { + game->deleteLater(); + } + } + return; } - setImportStatus(tr("Heroic import complete: %1 games found").arg(games.count())); - setImporting(false); - saveLibrary(); - Q_EMIT importCompleted(games.count()); + for (Game *game : games) { + if (game) { + self->m_gameModel->addGame(game); + } + } + self->setImportStatus(self->tr("Heroic import complete: %1 games found").arg(games.count())); + self->setImporting(false); + self->saveLibrary(); + Q_EMIT self->importCompleted(games.count()); }, Qt::QueuedConnection); }); @@ -827,31 +899,55 @@ void App::importFromHeroic() void App::importFromDesktop() { - if (m_importing) + if (m_importing || m_shuttingDown.load()) return; setImporting(true); setImportStatus(tr("Scanning desktop entries...")); - [[maybe_unused]] auto future = QtConcurrent::run([this]() { + [[maybe_unused]] auto future = QtConcurrent::run([self = QPointer(this)]() { + if (!self || self->m_shuttingDown.load()) { + return; + } + DesktopImporter importer; QList games = importer.importGames(); + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + delete game; + } + return; + } + + QThread *appThread = self->thread(); for (Game *game : games) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } } QMetaObject::invokeMethod( - this, - [this, games]() { - for (Game *game : games) { - m_gameModel->addGame(game); + self.data(), + [self, games]() { + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + if (game) { + game->deleteLater(); + } + } + return; } - setImportStatus(tr("Desktop import complete: %1 games found").arg(games.count())); - setImporting(false); - saveLibrary(); - Q_EMIT importCompleted(games.count()); + for (Game *game : games) { + if (game) { + self->m_gameModel->addGame(game); + } + } + self->setImportStatus(self->tr("Desktop import complete: %1 games found").arg(games.count())); + self->setImporting(false); + self->saveLibrary(); + Q_EMIT self->importCompleted(games.count()); }, Qt::QueuedConnection); }); @@ -859,31 +955,55 @@ void App::importFromDesktop() void App::importFromBottles() { - if (m_importing) + if (m_importing || m_shuttingDown.load()) return; setImporting(true); setImportStatus(tr("Scanning Bottles...")); - [[maybe_unused]] auto future = QtConcurrent::run([this]() { + [[maybe_unused]] auto future = QtConcurrent::run([self = QPointer(this)]() { + if (!self || self->m_shuttingDown.load()) { + return; + } + BottlesImporter importer; QList games = importer.importGames(); + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + delete game; + } + return; + } + + QThread *appThread = self->thread(); for (Game *game : games) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } } QMetaObject::invokeMethod( - this, - [this, games]() { - for (Game *game : games) { - m_gameModel->addGame(game); + self.data(), + [self, games]() { + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + if (game) { + game->deleteLater(); + } + } + return; } - setImportStatus(tr("Bottles import complete: %1 games found").arg(games.count())); - setImporting(false); - saveLibrary(); - Q_EMIT importCompleted(games.count()); + for (Game *game : games) { + if (game) { + self->m_gameModel->addGame(game); + } + } + self->setImportStatus(self->tr("Bottles import complete: %1 games found").arg(games.count())); + self->setImporting(false); + self->saveLibrary(); + Q_EMIT self->importCompleted(games.count()); }, Qt::QueuedConnection); }); @@ -891,31 +1011,55 @@ void App::importFromBottles() void App::importFromFlatpak() { - if (m_importing) + if (m_importing || m_shuttingDown.load()) return; setImporting(true); setImportStatus(tr("Scanning Flatpak games...")); - [[maybe_unused]] auto future = QtConcurrent::run([this]() { + [[maybe_unused]] auto future = QtConcurrent::run([self = QPointer(this)]() { + if (!self || self->m_shuttingDown.load()) { + return; + } + FlatpakImporter importer; QList games = importer.importGames(); + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + delete game; + } + return; + } + + QThread *appThread = self->thread(); for (Game *game : games) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } } QMetaObject::invokeMethod( - this, - [this, games]() { - for (Game *game : games) { - m_gameModel->addGame(game); + self.data(), + [self, games]() { + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + if (game) { + game->deleteLater(); + } + } + return; } - setImportStatus(tr("Flatpak import complete: %1 games found").arg(games.count())); - setImporting(false); - saveLibrary(); - Q_EMIT importCompleted(games.count()); + for (Game *game : games) { + if (game) { + self->m_gameModel->addGame(game); + } + } + self->setImportStatus(self->tr("Flatpak import complete: %1 games found").arg(games.count())); + self->setImporting(false); + self->saveLibrary(); + Q_EMIT self->importCompleted(games.count()); }, Qt::QueuedConnection); }); @@ -923,31 +1067,55 @@ void App::importFromFlatpak() void App::importFromItch() { - if (m_importing) + if (m_importing || m_shuttingDown.load()) return; setImporting(true); setImportStatus(tr("Scanning itch.io library...")); - [[maybe_unused]] auto future = QtConcurrent::run([this]() { + [[maybe_unused]] auto future = QtConcurrent::run([self = QPointer(this)]() { + if (!self || self->m_shuttingDown.load()) { + return; + } + ItchImporter importer; QList games = importer.importGames(); + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + delete game; + } + return; + } + + QThread *appThread = self->thread(); for (Game *game : games) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } } QMetaObject::invokeMethod( - this, - [this, games]() { - for (Game *game : games) { - m_gameModel->addGame(game); + self.data(), + [self, games]() { + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + if (game) { + game->deleteLater(); + } + } + return; } - setImportStatus(tr("itch.io import complete: %1 games found").arg(games.count())); - setImporting(false); - saveLibrary(); - Q_EMIT importCompleted(games.count()); + for (Game *game : games) { + if (game) { + self->m_gameModel->addGame(game); + } + } + self->setImportStatus(self->tr("itch.io import complete: %1 games found").arg(games.count())); + self->setImporting(false); + self->saveLibrary(); + Q_EMIT self->importCompleted(games.count()); }, Qt::QueuedConnection); }); @@ -955,31 +1123,55 @@ void App::importFromItch() void App::importFromLegendary() { - if (m_importing) + if (m_importing || m_shuttingDown.load()) return; setImporting(true); setImportStatus(tr("Scanning Legendary library...")); - [[maybe_unused]] auto future = QtConcurrent::run([this]() { + [[maybe_unused]] auto future = QtConcurrent::run([self = QPointer(this)]() { + if (!self || self->m_shuttingDown.load()) { + return; + } + LegendaryImporter importer; QList games = importer.importGames(); + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + delete game; + } + return; + } + + QThread *appThread = self->thread(); for (Game *game : games) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } } QMetaObject::invokeMethod( - this, - [this, games]() { - for (Game *game : games) { - m_gameModel->addGame(game); + self.data(), + [self, games]() { + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + if (game) { + game->deleteLater(); + } + } + return; } - setImportStatus(tr("Legendary import complete: %1 games found").arg(games.count())); - setImporting(false); - saveLibrary(); - Q_EMIT importCompleted(games.count()); + for (Game *game : games) { + if (game) { + self->m_gameModel->addGame(game); + } + } + self->setImportStatus(self->tr("Legendary import complete: %1 games found").arg(games.count())); + self->setImporting(false); + self->saveLibrary(); + Q_EMIT self->importCompleted(games.count()); }, Qt::QueuedConnection); }); @@ -987,31 +1179,55 @@ void App::importFromLegendary() void App::importFromRetroArch() { - if (m_importing) + if (m_importing || m_shuttingDown.load()) return; setImporting(true); setImportStatus(tr("Scanning RetroArch playlists...")); - [[maybe_unused]] auto future = QtConcurrent::run([this]() { + [[maybe_unused]] auto future = QtConcurrent::run([self = QPointer(this)]() { + if (!self || self->m_shuttingDown.load()) { + return; + } + RetroArchImporter importer; QList games = importer.importGames(); + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + delete game; + } + return; + } + + QThread *appThread = self->thread(); for (Game *game : games) { - game->moveToThread(this->thread()); - game->setParent(nullptr); + if (game) { + game->moveToThread(appThread); + game->setParent(nullptr); + } } QMetaObject::invokeMethod( - this, - [this, games]() { - for (Game *game : games) { - m_gameModel->addGame(game); + self.data(), + [self, games]() { + if (!self || self->m_shuttingDown.load()) { + for (Game *game : games) { + if (game) { + game->deleteLater(); + } + } + return; } - setImportStatus(tr("RetroArch import complete: %1 games found").arg(games.count())); - setImporting(false); - saveLibrary(); - Q_EMIT importCompleted(games.count()); + for (Game *game : games) { + if (game) { + self->m_gameModel->addGame(game); + } + } + self->setImportStatus(self->tr("RetroArch import complete: %1 games found").arg(games.count())); + self->setImporting(false); + self->saveLibrary(); + Q_EMIT self->importCompleted(games.count()); }, Qt::QueuedConnection); });