Core: Fix Game object lifetime

Use deleteLater() for Game and QProcess objects to avoid deleting
QObject instances at unsafe times.

Add helpers to detect/remove games by platform prefix, used by the
import workflow to avoid re-importing content.
This commit is contained in:
Marco Allegretti 2026-01-24 13:50:54 +01:00
parent 05abbf329b
commit 0897aa8769
3 changed files with 89 additions and 4 deletions

View file

@ -22,8 +22,11 @@ GameLauncher::~GameLauncher()
process->disconnect();
process->terminate();
process->waitForFinished(3000);
delete process;
process->deleteLater();
}
m_runningGames.clear();
m_processToGame.clear();
}
bool GameLauncher::hasRunningGames() const

View file

@ -202,7 +202,10 @@ void GameModel::addGame(Game *game)
// Check for duplicates
for (Game *existing : m_games) {
if (existing->id() == game->id()) {
delete game;
if (!game->parent()) {
game->setParent(this);
}
game->deleteLater();
return;
}
}
@ -289,7 +292,10 @@ void GameModel::removeGame(const QString &id)
endRemoveRows();
}
delete m_games.takeAt(i);
Game *game = m_games.takeAt(i);
if (game) {
game->deleteLater();
}
Q_EMIT countChanged();
return;
}
@ -317,7 +323,11 @@ Game *GameModel::gameById(const QString &id) const
void GameModel::clear()
{
beginResetModel();
qDeleteAll(m_games);
for (Game *game : m_games) {
if (game) {
game->deleteLater();
}
}
m_games.clear();
m_filteredGames.clear();
endResetModel();
@ -341,6 +351,76 @@ QList<Game *> GameModel::allGames() const
return m_games;
}
bool GameModel::hasPlatformPrefix(const QString &platformPrefix) const
{
if (platformPrefix.isEmpty()) {
return false;
}
for (Game *game : m_games) {
if (!game) {
continue;
}
if (game->platform().startsWith(platformPrefix)) {
return true;
}
}
return false;
}
int GameModel::removeByPlatformPrefix(const QString &platformPrefix)
{
if (platformPrefix.isEmpty()) {
return 0;
}
bool hasMatch = false;
for (Game *game : m_games) {
if (!game) {
continue;
}
if (game->platform().startsWith(platformPrefix)) {
hasMatch = true;
break;
}
}
if (!hasMatch) {
return 0;
}
beginResetModel();
int removed = 0;
for (int i = m_games.count() - 1; i >= 0; --i) {
Game *game = m_games.at(i);
if (!game) {
continue;
}
if (game->platform().startsWith(platformPrefix)) {
m_games.takeAt(i)->deleteLater();
removed++;
}
}
m_filteredGames.clear();
for (Game *game : m_games) {
if (matchesFilter(game)) {
m_filteredGames.append(game);
}
}
applySort();
endResetModel();
if (removed > 0) {
Q_EMIT countChanged();
}
return removed;
}
bool GameModel::matchesFilter(Game *game) const
{
if (!m_showHidden && game->hidden()) {

View file

@ -83,6 +83,8 @@ public:
Q_INVOKABLE Game *gameById(const QString &id) const;
Q_INVOKABLE void clear();
Q_INVOKABLE QStringList platforms() const;
Q_INVOKABLE bool hasPlatformPrefix(const QString &platformPrefix) const;
Q_INVOKABLE int removeByPlatformPrefix(const QString &platformPrefix);
QList<Game *> allGames() const;