From 365c3b31cb2e5516151631844397a2b4c310eb5b Mon Sep 17 00:00:00 2001 From: Marco Allegretti Date: Fri, 30 Jan 2026 14:07:58 +0100 Subject: [PATCH] Use global couch mode for profiles Select the couch launch profile based on effective UI mode so profile choice is consistent across games. Update details and edit UI to toggle and reflect couch mode globally, and fix duplicate QML property declarations. --- src/game.cpp | 11 ++++++++--- src/game.h | 1 + src/gamelauncher.cpp | 35 +++++++++++++++++++++++++++++++++-- src/qml/GameDetailsSheet.qml | 32 +++++++++++++++++++++++++------- src/qml/GameEditDialog.qml | 7 ++++++- 5 files changed, 73 insertions(+), 13 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 22b7362..964222a 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -251,6 +251,11 @@ void Game::setLaunchProfileConfig(const QString &profileId, const QVariantMap &c } QVariantMap Game::effectiveLaunchConfig() const +{ + return effectiveLaunchConfigForProfile(m_activeLaunchProfile); +} + +QVariantMap Game::effectiveLaunchConfigForProfile(const QString &profileId) const { QVariantMap result; @@ -267,12 +272,12 @@ QVariantMap Game::effectiveLaunchConfig() const result.insert(QStringLiteral("env"), m_launchEnv); } - const QString profileId = m_activeLaunchProfile.trimmed(); - if (profileId.isEmpty() || profileId == QLatin1String("default")) { + const QString id = profileId.trimmed(); + if (id.isEmpty() || id == QLatin1String("default")) { return result; } - const QVariantMap profileConfig = launchProfileConfig(profileId); + const QVariantMap profileConfig = launchProfileConfig(id); if (profileConfig.isEmpty()) { return result; } diff --git a/src/game.h b/src/game.h index 7d02266..00ce69f 100644 --- a/src/game.h +++ b/src/game.h @@ -88,6 +88,7 @@ public: Q_INVOKABLE QVariantMap launchProfileConfig(const QString &profileId) const; Q_INVOKABLE void setLaunchProfileConfig(const QString &profileId, const QVariantMap &config); + QVariantMap effectiveLaunchConfigForProfile(const QString &profileId) const; QVariantMap effectiveLaunchConfig() const; QString platform() const; diff --git a/src/gamelauncher.cpp b/src/gamelauncher.cpp index af90fe9..53cd5e4 100644 --- a/src/gamelauncher.cpp +++ b/src/gamelauncher.cpp @@ -3,6 +3,8 @@ #include "gamelauncher.h" #include "app.h" +#include "gamepadmanager.h" +#include "inputmanager.h" #include #include @@ -108,6 +110,33 @@ static QString discoverDefaultProtonExecutable() return cached; } +static QString profileIdForCurrentUiMode() +{ + const Config *config = App::instance() ? App::instance()->config() : nullptr; + if (!config) { + return QStringLiteral("default"); + } + + if (config->uiMode() == Config::Couch) { + return QStringLiteral("couch"); + } + + if (config->uiMode() == Config::Auto) { + GamepadManager *pad = GamepadManager::instance(); + InputManager *input = InputManager::instance(); + + if (pad && pad->connected()) { + const bool activeGamepad = input && input->activeInput() == InputManager::Gamepad; + const bool noKeyboardMouse = input && !input->hasSeenKeyboardMouse(); + if (activeGamepad || noKeyboardMouse) { + return QStringLiteral("couch"); + } + } + } + + return QStringLiteral("default"); +} + GameLauncher::GameLauncher(QObject *parent) : QObject(parent) { @@ -153,7 +182,8 @@ QVariantMap GameLauncher::resolveLaunchInfo(Game *game) const return info; } - const QVariantMap effectiveLaunchConfig = game->effectiveLaunchConfig(); + const QString profileId = profileIdForCurrentUiMode(); + const QVariantMap effectiveLaunchConfig = game->effectiveLaunchConfigForProfile(profileId); const QString runner = effectiveLaunchConfig.value(QStringLiteral("runner")).toString().trimmed(); const QString runnerPath = effectiveLaunchConfig.value(QStringLiteral("runnerPath")).toString().trimmed(); const QString prefixPath = effectiveLaunchConfig.value(QStringLiteral("prefixPath")).toString().trimmed(); @@ -298,7 +328,8 @@ void GameLauncher::launchGame(Game *game) return; } - const QVariantMap effectiveLaunchConfig = game->effectiveLaunchConfig(); + const QString profileId = profileIdForCurrentUiMode(); + const QVariantMap effectiveLaunchConfig = game->effectiveLaunchConfigForProfile(profileId); const QString runner = effectiveLaunchConfig.value(QStringLiteral("runner")).toString().trimmed(); const QString runnerPath = effectiveLaunchConfig.value(QStringLiteral("runnerPath")).toString().trimmed(); const QString prefixPath = effectiveLaunchConfig.value(QStringLiteral("prefixPath")).toString().trimmed(); diff --git a/src/qml/GameDetailsSheet.qml b/src/qml/GameDetailsSheet.qml index 4bb593f..f3a553d 100644 --- a/src/qml/GameDetailsSheet.qml +++ b/src/qml/GameDetailsSheet.qml @@ -12,7 +12,18 @@ import org.kde.alakarte Kirigami.OverlaySheet { id: detailsSheet - property var game + property var game: null + property int lastNonCouchUiMode: Config.Auto + + readonly property bool effectiveCouchMode: { + if (App.config.uiMode === Config.Couch) return true + if (App.config.uiMode !== Config.Auto) return false + if (GamepadManager.connected) { + if (InputManager.activeInput === InputManager.Gamepad) return true + if (!InputManager.hasSeenKeyboardMouse) return true + } + return false + } readonly property var screenshotsModel: game ? App.mediaManager.screenshotsModel(game) : null @@ -419,13 +430,20 @@ Kirigami.OverlaySheet { } QQC2.Button { - icon.name: "preferences-other" - text: game && game.activeLaunchProfile === "couch" ? i18n("Profile: Couch") : i18n("Profile: Default") + icon.name: "view-fullscreen" + text: detailsSheet.effectiveCouchMode ? i18n("Couch mode: On") : i18n("Couch mode: Off") display: detailsSheet.useCompactLayout ? QQC2.AbstractButton.TextUnderIcon : QQC2.AbstractButton.TextBesideIcon - enabled: !!game - onClicked: if (game) { - game.activeLaunchProfile = (game.activeLaunchProfile === "couch") ? "default" : "couch" - App.saveLibrary() + onClicked: { + if (detailsSheet.effectiveCouchMode) { + if (detailsSheet.lastNonCouchUiMode === Config.Auto) { + App.config.uiMode = Config.Desktop + } else { + App.config.uiMode = detailsSheet.lastNonCouchUiMode + } + } else { + detailsSheet.lastNonCouchUiMode = App.config.uiMode + App.config.uiMode = Config.Couch + } } } diff --git a/src/qml/GameEditDialog.qml b/src/qml/GameEditDialog.qml index 65188a6..8069b1c 100644 --- a/src/qml/GameEditDialog.qml +++ b/src/qml/GameEditDialog.qml @@ -248,7 +248,12 @@ Kirigami.Dialog { executableField.text = game.launchCommand || "" workingDirField.text = game.workingDirectory || "" - dialog.editProfileId = game.activeLaunchProfile === "couch" ? "couch" : "default" + dialog.editProfileId = (App.config.uiMode === Config.Couch + || (App.config.uiMode === Config.Auto + && GamepadManager.connected + && (InputManager.activeInput === InputManager.Gamepad || !InputManager.hasSeenKeyboardMouse))) + ? "couch" + : "default" profileCombo.currentIndex = dialog.profileIndexFromId(dialog.editProfileId) dialog.loadProfileFields() } else {