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
{
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;
}

View file

@ -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;

View file

@ -3,6 +3,8 @@
#include "gamelauncher.h"
#include "app.h"
#include "gamepadmanager.h"
#include "inputmanager.h"
#include <QCoreApplication>
#include <QDateTime>
@ -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();

View file

@ -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
}
}
}

View file

@ -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 {