mirror of
https://invent.kde.org/marcoa/a-la-karte.git
synced 2026-03-27 01:03:09 +00:00
Compare commits
No commits in common. "cca49615d68bd8b07c554e4cc791b9e9aab81a1d" and "b0d09be497a694b51ab5172f8d67da25c1e22454" have entirely different histories.
cca49615d6
...
b0d09be497
11 changed files with 465 additions and 937 deletions
1228
src/app.cpp
1228
src/app.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
@ -38,8 +36,6 @@ public:
|
||||||
static App *instance();
|
static App *instance();
|
||||||
static App *create(QQmlEngine *engine, QJSEngine *scriptEngine);
|
static App *create(QQmlEngine *engine, QJSEngine *scriptEngine);
|
||||||
|
|
||||||
~App() override;
|
|
||||||
|
|
||||||
GameModel *gameModel() const;
|
GameModel *gameModel() const;
|
||||||
GameLauncher *launcher() const;
|
GameLauncher *launcher() const;
|
||||||
RunnerManagerClient *runnerManager() const;
|
RunnerManagerClient *runnerManager() const;
|
||||||
|
|
@ -94,8 +90,6 @@ private:
|
||||||
QString m_importStatus;
|
QString m_importStatus;
|
||||||
QHash<QString, QJsonObject> m_removedGames;
|
QHash<QString, QJsonObject> m_removedGames;
|
||||||
|
|
||||||
std::atomic_bool m_shuttingDown{false};
|
|
||||||
|
|
||||||
void setImporting(bool importing);
|
void setImporting(bool importing);
|
||||||
void setImportStatus(const QString &status);
|
void setImportStatus(const QString &status);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
#include "gamecenterdaemon.h"
|
#include "gamecenterdaemon.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QDBusArgument>
|
#include <QDBusArgument>
|
||||||
#include <QDBusConnection>
|
#include <QDBusConnection>
|
||||||
#include <QDBusConnectionInterface>
|
#include <QDBusConnectionInterface>
|
||||||
|
|
@ -879,48 +878,6 @@ GameCenterDaemon::GameCenterDaemon(QObject *parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
GameCenterDaemon::~GameCenterDaemon()
|
|
||||||
{
|
|
||||||
prepareForShutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameCenterDaemon::prepareForShutdown()
|
|
||||||
{
|
|
||||||
for (auto it = m_sessions.begin(); it != m_sessions.end(); ++it) {
|
|
||||||
if (it.value().scanner) {
|
|
||||||
it.value().scanner->cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
QPointer<QProcess> proc = it.value().process;
|
|
||||||
it.value().process = nullptr;
|
|
||||||
if (proc) {
|
|
||||||
proc->disconnect(this);
|
|
||||||
connect(proc, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), proc, &QObject::deleteLater);
|
|
||||||
if (proc->state() != QProcess::NotRunning) {
|
|
||||||
proc->setParent(nullptr);
|
|
||||||
} else {
|
|
||||||
proc->deleteLater();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it.value().scanner) {
|
|
||||||
it.value().scanner->disconnect(this);
|
|
||||||
it.value().scanner->deleteLater();
|
|
||||||
it.value().scanner = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto it = m_unitPathWatchers.begin(); it != m_unitPathWatchers.end(); ++it) {
|
|
||||||
if (QObject *watcher = it.value()) {
|
|
||||||
watcher->deleteLater();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_unitPathWatchers.clear();
|
|
||||||
m_unitPathToSessionId.clear();
|
|
||||||
m_unitNameToSessionId.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GameCenterDaemon::init()
|
bool GameCenterDaemon::init()
|
||||||
{
|
{
|
||||||
QDBusConnection bus = QDBusConnection::sessionBus();
|
QDBusConnection bus = QDBusConnection::sessionBus();
|
||||||
|
|
@ -940,10 +897,6 @@ bool GameCenterDaemon::init()
|
||||||
|
|
||||||
recoverExistingSessions();
|
recoverExistingSessions();
|
||||||
|
|
||||||
if (QCoreApplication::instance()) {
|
|
||||||
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &GameCenterDaemon::prepareForShutdown);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1279,7 +1232,7 @@ QString GameCenterDaemon::launchDirect(const QVariantMap &launchSpec)
|
||||||
}
|
}
|
||||||
|
|
||||||
process->start(program, args);
|
process->start(program, args);
|
||||||
if (!process->waitForStarted(5000)) {
|
if (!process->waitForStarted()) {
|
||||||
const QVariantMap ctx = {
|
const QVariantMap ctx = {
|
||||||
{QStringLiteral("command"), command},
|
{QStringLiteral("command"), command},
|
||||||
{QStringLiteral("program"), program},
|
{QStringLiteral("program"), program},
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ class GameCenterDaemon : public QObject
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit GameCenterDaemon(QObject *parent = nullptr);
|
explicit GameCenterDaemon(QObject *parent = nullptr);
|
||||||
~GameCenterDaemon() override;
|
|
||||||
|
|
||||||
bool init();
|
bool init();
|
||||||
|
|
||||||
|
|
@ -77,8 +76,6 @@ private:
|
||||||
void handleSystemdUnitPropertiesChanged(const QDBusObjectPath &unitPath, const QVariantMap &changedProperties);
|
void handleSystemdUnitPropertiesChanged(const QDBusObjectPath &unitPath, const QVariantMap &changedProperties);
|
||||||
void removeSessionInternal(const QString &sessionId, const QString &finalState);
|
void removeSessionInternal(const QString &sessionId, const QString &finalState);
|
||||||
|
|
||||||
void prepareForShutdown();
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void handleSystemdUnitNew(const QString &unitName, const QDBusObjectPath &unitPath);
|
void handleSystemdUnitNew(const QString &unitName, const QDBusObjectPath &unitPath);
|
||||||
void handleSystemdUnitRemoved(const QString &unitName, const QDBusObjectPath &unitPath);
|
void handleSystemdUnitRemoved(const QString &unitName, const QDBusObjectPath &unitPath);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QSaveFile>
|
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
@ -88,6 +87,14 @@ static QString gamepadTypeToString(SDL_GamepadType t)
|
||||||
return QStringLiteral("unknown");
|
return QStringLiteral("unknown");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QVariantMap unwrapVariantMap(QVariant v)
|
||||||
|
{
|
||||||
|
if (v.canConvert<QVariantMap>()) {
|
||||||
|
return v.toMap();
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap InputDaemon::Profile::toVariantMap() const
|
QVariantMap InputDaemon::Profile::toVariantMap() const
|
||||||
|
|
@ -266,10 +273,7 @@ void InputDaemon::loadProfiles()
|
||||||
bool InputDaemon::saveProfiles() const
|
bool InputDaemon::saveProfiles() const
|
||||||
{
|
{
|
||||||
const QString path = profilesPath();
|
const QString path = profilesPath();
|
||||||
const QString dirPath = QFileInfo(path).absolutePath();
|
QDir().mkpath(QFileInfo(path).absolutePath());
|
||||||
if (!QDir().mkpath(dirPath)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonArray profiles;
|
QJsonArray profiles;
|
||||||
for (const Profile &p : m_profiles) {
|
for (const Profile &p : m_profiles) {
|
||||||
|
|
@ -285,17 +289,13 @@ bool InputDaemon::saveProfiles() const
|
||||||
root.insert(QStringLiteral("profiles"), profiles);
|
root.insert(QStringLiteral("profiles"), profiles);
|
||||||
root.insert(QStringLiteral("assignments"), assignments);
|
root.insert(QStringLiteral("assignments"), assignments);
|
||||||
|
|
||||||
QSaveFile f(path);
|
QFile f(path);
|
||||||
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QByteArray payload = QJsonDocument(root).toJson();
|
f.write(QJsonDocument(root).toJson());
|
||||||
if (f.write(payload) != payload.size()) {
|
return true;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return f.commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InputDaemon::Profile InputDaemon::profileById(const QString &profileId) const
|
InputDaemon::Profile InputDaemon::profileById(const QString &profileId) const
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ QList<Game *> LutrisImporter::importGames()
|
||||||
QProcess process;
|
QProcess process;
|
||||||
process.start(lutrisPath, {QStringLiteral("-lo"), QStringLiteral("--json")});
|
process.start(lutrisPath, {QStringLiteral("-lo"), QStringLiteral("--json")});
|
||||||
|
|
||||||
if (process.waitForStarted(5000) && process.waitForFinished(30000)) {
|
if (process.waitForFinished(30000)) {
|
||||||
QByteArray output = process.readAllStandardOutput();
|
QByteArray output = process.readAllStandardOutput();
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(output);
|
QJsonDocument doc = QJsonDocument::fromJson(output);
|
||||||
|
|
||||||
|
|
@ -139,14 +139,6 @@ QList<Game *> LutrisImporter::importGames()
|
||||||
Q_EMIT importProgress(current, total);
|
Q_EMIT importProgress(current, total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (process.state() != QProcess::NotRunning) {
|
|
||||||
process.terminate();
|
|
||||||
if (!process.waitForFinished(3000)) {
|
|
||||||
process.kill();
|
|
||||||
process.waitForFinished(3000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,10 +115,7 @@ Kirigami.Dialog {
|
||||||
|
|
||||||
readonly property bool anyConfirmOpen: !!(deletePrefixConfirmDialog && deletePrefixConfirmDialog.opened)
|
readonly property bool anyConfirmOpen: !!(deletePrefixConfirmDialog && deletePrefixConfirmDialog.opened)
|
||||||
|
|
||||||
readonly property bool anyMenuOpen: {
|
readonly property bool anyMenuOpen: !!(runnerCombo && runnerCombo.popup && runnerCombo.popup.visible)
|
||||||
if (!runnerCombo || !runnerCombo.popup) return false
|
|
||||||
return runnerCombo.popup.visible === true
|
|
||||||
}
|
|
||||||
|
|
||||||
function currentConfirmDialog() {
|
function currentConfirmDialog() {
|
||||||
if (deletePrefixConfirmDialog && deletePrefixConfirmDialog.opened) return deletePrefixConfirmDialog
|
if (deletePrefixConfirmDialog && deletePrefixConfirmDialog.opened) return deletePrefixConfirmDialog
|
||||||
|
|
@ -136,7 +133,7 @@ Kirigami.Dialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeCurrentMenu() {
|
function closeCurrentMenu() {
|
||||||
if (runnerCombo && runnerCombo.popup && runnerCombo.popup.visible === true) {
|
if (runnerCombo && runnerCombo.popup && runnerCombo.popup.visible) {
|
||||||
runnerCombo.popup.close()
|
runnerCombo.popup.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -328,6 +328,8 @@ Kirigami.ApplicationWindow {
|
||||||
|
|
||||||
footer: Item {
|
footer: Item {
|
||||||
implicitWidth: root.width
|
implicitWidth: root.width
|
||||||
|
anchors.left: parent ? parent.left : undefined
|
||||||
|
anchors.right: parent ? parent.right : undefined
|
||||||
|
|
||||||
implicitHeight: footerBar.implicitHeight
|
implicitHeight: footerBar.implicitHeight
|
||||||
height: implicitHeight
|
height: implicitHeight
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QSaveFile>
|
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
@ -202,10 +201,7 @@ void RunnerManagerDaemon::loadRegistry()
|
||||||
bool RunnerManagerDaemon::saveRegistry() const
|
bool RunnerManagerDaemon::saveRegistry() const
|
||||||
{
|
{
|
||||||
const QString path = registryPath();
|
const QString path = registryPath();
|
||||||
const QString dirPath = QFileInfo(path).absolutePath();
|
QDir().mkpath(QFileInfo(path).absolutePath());
|
||||||
if (!QDir().mkpath(dirPath)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonArray arr;
|
QJsonArray arr;
|
||||||
|
|
||||||
|
|
@ -225,17 +221,13 @@ bool RunnerManagerDaemon::saveRegistry() const
|
||||||
QJsonObject root;
|
QJsonObject root;
|
||||||
root.insert(QStringLiteral("runners"), arr);
|
root.insert(QStringLiteral("runners"), arr);
|
||||||
|
|
||||||
QSaveFile f(path);
|
QFile f(path);
|
||||||
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QByteArray payload = QJsonDocument(root).toJson(QJsonDocument::Indented);
|
f.write(QJsonDocument(root).toJson(QJsonDocument::Indented));
|
||||||
if (f.write(payload) != payload.size()) {
|
return true;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return f.commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString RunnerManagerDaemon::gameProfilesPath() const
|
QString RunnerManagerDaemon::gameProfilesPath() const
|
||||||
|
|
@ -275,10 +267,7 @@ void RunnerManagerDaemon::loadGameProfiles()
|
||||||
bool RunnerManagerDaemon::saveGameProfiles() const
|
bool RunnerManagerDaemon::saveGameProfiles() const
|
||||||
{
|
{
|
||||||
const QString path = gameProfilesPath();
|
const QString path = gameProfilesPath();
|
||||||
const QString dirPath = QFileInfo(path).absolutePath();
|
QDir().mkpath(QFileInfo(path).absolutePath());
|
||||||
if (!QDir().mkpath(dirPath)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonArray arr;
|
QJsonArray arr;
|
||||||
for (auto it = m_gameProfiles.constBegin(); it != m_gameProfiles.constEnd(); ++it) {
|
for (auto it = m_gameProfiles.constBegin(); it != m_gameProfiles.constEnd(); ++it) {
|
||||||
|
|
@ -292,17 +281,13 @@ bool RunnerManagerDaemon::saveGameProfiles() const
|
||||||
QJsonObject root;
|
QJsonObject root;
|
||||||
root.insert(QStringLiteral("profiles"), arr);
|
root.insert(QStringLiteral("profiles"), arr);
|
||||||
|
|
||||||
QSaveFile f(path);
|
QFile f(path);
|
||||||
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QByteArray payload = QJsonDocument(root).toJson(QJsonDocument::Indented);
|
f.write(QJsonDocument(root).toJson(QJsonDocument::Indented));
|
||||||
if (f.write(payload) != payload.size()) {
|
return true;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return f.commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap RunnerManagerDaemon::gameProfileForGameId(const QString &gameId) const
|
QVariantMap RunnerManagerDaemon::gameProfileForGameId(const QString &gameId) const
|
||||||
|
|
|
||||||
|
|
@ -152,23 +152,15 @@ void RunnerManagerClient::shutdownSpawnedRunnerDaemon()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QProcess *p = m_runnerdProcess;
|
if (m_runnerdProcess->state() == QProcess::NotRunning) {
|
||||||
const auto state = p->state();
|
|
||||||
if (state == QProcess::NotRunning) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid our finished() handler nulling the pointer while we're shutting down.
|
m_runnerdProcess->terminate();
|
||||||
p->disconnect(this);
|
if (!m_runnerdProcess->waitForFinished(1000)) {
|
||||||
|
m_runnerdProcess->kill();
|
||||||
p->terminate();
|
m_runnerdProcess->waitForFinished(1000);
|
||||||
if (!p->waitForFinished(3000)) {
|
|
||||||
p->kill();
|
|
||||||
p->waitForFinished(3000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p->deleteLater();
|
|
||||||
m_runnerdProcess = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunnerManagerClient::ensureRunnerDaemon()
|
void RunnerManagerClient::ensureRunnerDaemon()
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@
|
||||||
#include <KConfigGroup>
|
#include <KConfigGroup>
|
||||||
#include <KSharedConfig>
|
#include <KSharedConfig>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QSaveFile>
|
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QUrlQuery>
|
#include <QUrlQuery>
|
||||||
|
|
||||||
|
|
@ -297,28 +297,16 @@ void SteamGridDB::onImageDownloaded()
|
||||||
QString coversPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/covers");
|
QString coversPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/covers");
|
||||||
QDir dir(coversPath);
|
QDir dir(coversPath);
|
||||||
if (!dir.exists()) {
|
if (!dir.exists()) {
|
||||||
if (!dir.mkpath(coversPath)) {
|
dir.mkpath(coversPath);
|
||||||
Q_EMIT fetchError(game, QStringLiteral("Failed to create covers directory"));
|
|
||||||
m_processedGames++;
|
|
||||||
Q_EMIT fetchProgress(m_processedGames, m_totalGames);
|
|
||||||
processNextGame();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString fileName = game->id() + QStringLiteral(".jpg");
|
QString fileName = game->id() + QStringLiteral(".jpg");
|
||||||
QString filePath = coversPath + QStringLiteral("/") + fileName;
|
QString filePath = coversPath + QStringLiteral("/") + fileName;
|
||||||
|
|
||||||
const QByteArray payload = reply->readAll();
|
QFile file(filePath);
|
||||||
QSaveFile file(filePath);
|
if (file.open(QIODevice::WriteOnly)) {
|
||||||
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
file.write(reply->readAll());
|
||||||
if (file.write(payload) != payload.size() || !file.commit()) {
|
file.close();
|
||||||
Q_EMIT fetchError(game, QStringLiteral("Failed to save cover image"));
|
|
||||||
m_processedGames++;
|
|
||||||
Q_EMIT fetchProgress(m_processedGames, m_totalGames);
|
|
||||||
processNextGame();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QUrl localUrl = QUrl::fromLocalFile(filePath);
|
QUrl localUrl = QUrl::fromLocalFile(filePath);
|
||||||
game->setCoverUrl(localUrl);
|
game->setCoverUrl(localUrl);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue