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.
This commit is contained in:
Marco Allegretti 2026-01-30 14:07:58 +01:00
parent ec7d61e5b9
commit 365c3b31cb
5 changed files with 73 additions and 13 deletions

View file

@ -251,6 +251,11 @@ void Game::setLaunchProfileConfig(const QString &profileId, const QVariantMap &c
} }
QVariantMap Game::effectiveLaunchConfig() const QVariantMap Game::effectiveLaunchConfig() const
{
return effectiveLaunchConfigForProfile(m_activeLaunchProfile);
}
QVariantMap Game::effectiveLaunchConfigForProfile(const QString &profileId) const
{ {
QVariantMap result; QVariantMap result;
@ -267,12 +272,12 @@ QVariantMap Game::effectiveLaunchConfig() const
result.insert(QStringLiteral("env"), m_launchEnv); result.insert(QStringLiteral("env"), m_launchEnv);
} }
const QString profileId = m_activeLaunchProfile.trimmed(); const QString id = profileId.trimmed();
if (profileId.isEmpty() || profileId == QLatin1String("default")) { if (id.isEmpty() || id == QLatin1String("default")) {
return result; return result;
} }
const QVariantMap profileConfig = launchProfileConfig(profileId); const QVariantMap profileConfig = launchProfileConfig(id);
if (profileConfig.isEmpty()) { if (profileConfig.isEmpty()) {
return result; return result;
} }

View file

@ -88,6 +88,7 @@ public:
Q_INVOKABLE QVariantMap launchProfileConfig(const QString &profileId) const; Q_INVOKABLE QVariantMap launchProfileConfig(const QString &profileId) const;
Q_INVOKABLE void setLaunchProfileConfig(const QString &profileId, const QVariantMap &config); Q_INVOKABLE void setLaunchProfileConfig(const QString &profileId, const QVariantMap &config);
QVariantMap effectiveLaunchConfigForProfile(const QString &profileId) const;
QVariantMap effectiveLaunchConfig() const; QVariantMap effectiveLaunchConfig() const;
QString platform() const; QString platform() const;

View file

@ -3,6 +3,8 @@
#include "gamelauncher.h" #include "gamelauncher.h"
#include "app.h" #include "app.h"
#include "gamepadmanager.h"
#include "inputmanager.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QDateTime> #include <QDateTime>
@ -108,6 +110,33 @@ static QString discoverDefaultProtonExecutable()
return cached; 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) GameLauncher::GameLauncher(QObject *parent)
: QObject(parent) : QObject(parent)
{ {
@ -153,7 +182,8 @@ QVariantMap GameLauncher::resolveLaunchInfo(Game *game) const
return info; 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 runner = effectiveLaunchConfig.value(QStringLiteral("runner")).toString().trimmed();
const QString runnerPath = effectiveLaunchConfig.value(QStringLiteral("runnerPath")).toString().trimmed(); const QString runnerPath = effectiveLaunchConfig.value(QStringLiteral("runnerPath")).toString().trimmed();
const QString prefixPath = effectiveLaunchConfig.value(QStringLiteral("prefixPath")).toString().trimmed(); const QString prefixPath = effectiveLaunchConfig.value(QStringLiteral("prefixPath")).toString().trimmed();
@ -298,7 +328,8 @@ void GameLauncher::launchGame(Game *game)
return; 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 runner = effectiveLaunchConfig.value(QStringLiteral("runner")).toString().trimmed();
const QString runnerPath = effectiveLaunchConfig.value(QStringLiteral("runnerPath")).toString().trimmed(); const QString runnerPath = effectiveLaunchConfig.value(QStringLiteral("runnerPath")).toString().trimmed();
const QString prefixPath = effectiveLaunchConfig.value(QStringLiteral("prefixPath")).toString().trimmed(); const QString prefixPath = effectiveLaunchConfig.value(QStringLiteral("prefixPath")).toString().trimmed();

View file

@ -12,7 +12,18 @@ import org.kde.alakarte
Kirigami.OverlaySheet { Kirigami.OverlaySheet {
id: detailsSheet 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 readonly property var screenshotsModel: game ? App.mediaManager.screenshotsModel(game) : null
@ -419,13 +430,20 @@ Kirigami.OverlaySheet {
} }
QQC2.Button { QQC2.Button {
icon.name: "preferences-other" icon.name: "view-fullscreen"
text: game && game.activeLaunchProfile === "couch" ? i18n("Profile: Couch") : i18n("Profile: Default") text: detailsSheet.effectiveCouchMode ? i18n("Couch mode: On") : i18n("Couch mode: Off")
display: detailsSheet.useCompactLayout ? QQC2.AbstractButton.TextUnderIcon : QQC2.AbstractButton.TextBesideIcon display: detailsSheet.useCompactLayout ? QQC2.AbstractButton.TextUnderIcon : QQC2.AbstractButton.TextBesideIcon
enabled: !!game onClicked: {
onClicked: if (game) { if (detailsSheet.effectiveCouchMode) {
game.activeLaunchProfile = (game.activeLaunchProfile === "couch") ? "default" : "couch" if (detailsSheet.lastNonCouchUiMode === Config.Auto) {
App.saveLibrary() App.config.uiMode = Config.Desktop
} else {
App.config.uiMode = detailsSheet.lastNonCouchUiMode
}
} else {
detailsSheet.lastNonCouchUiMode = App.config.uiMode
App.config.uiMode = Config.Couch
}
} }
} }

View file

@ -248,7 +248,12 @@ Kirigami.Dialog {
executableField.text = game.launchCommand || "" executableField.text = game.launchCommand || ""
workingDirField.text = game.workingDirectory || "" 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) profileCombo.currentIndex = dialog.profileIndexFromId(dialog.editProfileId)
dialog.loadProfileFields() dialog.loadProfileFields()
} else { } else {