diff --git a/components/gamingshellplugin/gamelauncherprovider.cpp b/components/gamingshellplugin/gamelauncherprovider.cpp index 99bfd3ae..9bae988b 100644 --- a/components/gamingshellplugin/gamelauncherprovider.cpp +++ b/components/gamingshellplugin/gamelauncherprovider.cpp @@ -357,6 +357,21 @@ void GameLauncherProvider::refresh() m_allGames.clear(); + // Detect which third-party launchers are installed + const bool steamWas = m_steamAvailable; + const bool lutrisWas = m_lutrisAvailable; + const bool heroicWas = m_heroicAvailable; + m_steamAvailable = detectLauncher(QStringLiteral("steam"), + {QStringLiteral("com.valvesoftware.Steam")}, + {QDir::homePath() + QStringLiteral("/.steam/steam"), + QDir::homePath() + QStringLiteral("/.local/share/Steam"), + QDir::homePath() + QStringLiteral("/.var/app/com.valvesoftware.Steam/.local/share/Steam")}); + m_lutrisAvailable = + detectLauncher(QStringLiteral("lutris"), {QStringLiteral("net.lutris.Lutris")}, {QDir::homePath() + QStringLiteral("/.local/share/lutris")}); + m_heroicAvailable = + detectLauncher(QStringLiteral("heroic"), {QStringLiteral("com.heroicgameslauncher.hgl")}, {QDir::homePath() + QStringLiteral("/.config/heroic")}); + if (m_steamAvailable != steamWas || m_lutrisAvailable != lutrisWas || m_heroicAvailable != heroicWas) + Q_EMIT launcherAvailabilityChanged(); loadDesktopGames(); loadSteamGames(); loadLutrisGames(); @@ -904,6 +919,37 @@ bool GameLauncherProvider::mangohudAvailable() const return m_mangohudAvailable; } +bool GameLauncherProvider::steamAvailable() const +{ + return m_steamAvailable; +} + +bool GameLauncherProvider::lutrisAvailable() const +{ + return m_lutrisAvailable; +} + +bool GameLauncherProvider::heroicAvailable() const +{ + return m_heroicAvailable; +} + +// static +bool GameLauncherProvider::detectLauncher(const QString &executable, const QStringList &flatpakAppIds, const QStringList &dataDirs) +{ + if (!QStandardPaths::findExecutable(executable).isEmpty()) + return true; + for (const QString &appId : flatpakAppIds) { + if (QDir(QDir::homePath() + QStringLiteral("/.var/app/") + appId).exists()) + return true; + } + for (const QString &dir : dataDirs) { + if (QDir(dir).exists()) + return true; + } + return false; +} + int GameLauncherProvider::fpsLimit() const { return m_fpsLimit; diff --git a/components/gamingshellplugin/gamelauncherprovider.h b/components/gamingshellplugin/gamelauncherprovider.h index 32bf6fcd..99896efc 100644 --- a/components/gamingshellplugin/gamelauncherprovider.h +++ b/components/gamingshellplugin/gamelauncherprovider.h @@ -27,6 +27,9 @@ class GameLauncherProvider : public QAbstractListModel Q_PROPERTY(QString sourceFilter READ sourceFilter WRITE setSourceFilter NOTIFY sourceFilterChanged) Q_PROPERTY(bool overlayEnabled READ overlayEnabled WRITE setOverlayEnabled NOTIFY overlayEnabledChanged) Q_PROPERTY(bool mangohudAvailable READ mangohudAvailable NOTIFY mangohudAvailableChanged) + Q_PROPERTY(bool steamAvailable READ steamAvailable NOTIFY launcherAvailabilityChanged) + Q_PROPERTY(bool lutrisAvailable READ lutrisAvailable NOTIFY launcherAvailabilityChanged) + Q_PROPERTY(bool heroicAvailable READ heroicAvailable NOTIFY launcherAvailabilityChanged) Q_PROPERTY(int fpsLimit READ fpsLimit WRITE setFpsLimit NOTIFY fpsLimitChanged) Q_PROPERTY(bool launchPending READ launchPending NOTIFY launchPendingChanged) Q_PROPERTY(QString pendingLaunchName READ pendingLaunchName NOTIFY launchPendingChanged) @@ -61,6 +64,9 @@ public: bool overlayEnabled() const; void setOverlayEnabled(bool enabled); bool mangohudAvailable() const; + bool steamAvailable() const; + bool lutrisAvailable() const; + bool heroicAvailable() const; int fpsLimit() const; void setFpsLimit(int limit); bool launchPending() const; @@ -89,6 +95,7 @@ Q_SIGNALS: void sourceFilterChanged(); void overlayEnabledChanged(); void mangohudAvailableChanged(); + void launcherAvailabilityChanged(); void fpsLimitChanged(); void launchPendingChanged(); void lastLaunchErrorChanged(); @@ -137,6 +144,11 @@ private: int m_fpsLimit = 0; bool m_mangohudAvailable = false; QString m_mangohudPath; + bool m_steamAvailable = false; + bool m_lutrisAvailable = false; + bool m_heroicAvailable = false; + + static bool detectLauncher(const QString &executable, const QStringList &flatpakAppIds, const QStringList &dataDirs); QSet m_pinnedGames; bool m_launchPending = false; QString m_pendingLaunchName; diff --git a/containments/homescreens/folio/qml/gaming/GameCenterOverlay.qml b/containments/homescreens/folio/qml/gaming/GameCenterOverlay.qml index 5df0a6b8..7579c8c9 100644 --- a/containments/homescreens/folio/qml/gaming/GameCenterOverlay.qml +++ b/containments/homescreens/folio/qml/gaming/GameCenterOverlay.qml @@ -422,8 +422,14 @@ Window { } } - // Cycle through source filter tabs. - readonly property var _sourceFilters: ["", "steam", "desktop", "waydroid", "lutris", "heroic"] + // Cycle through source filter tabs (only includes installed launcher sources). + readonly property var _sourceFilters: { + var filters = ["", "desktop", "waydroid"] + if (GamingShell.GameLauncherProvider.steamAvailable) filters.splice(1, 0, "steam") + if (GamingShell.GameLauncherProvider.lutrisAvailable) filters.push("lutris") + if (GamingShell.GameLauncherProvider.heroicAvailable) filters.push("heroic") + return filters + } function cycleSourceFilter(direction) { var current = _sourceFilters.indexOf( GamingShell.GameLauncherProvider.sourceFilter) @@ -749,35 +755,26 @@ Window { id: sourceFilterBar Layout.alignment: Qt.AlignVCenter - QQC2.TabButton { - text: i18n("All") - width: implicitWidth - onClicked: GamingShell.GameLauncherProvider.sourceFilter = "" - } - QQC2.TabButton { - text: "Steam" - width: implicitWidth - onClicked: GamingShell.GameLauncherProvider.sourceFilter = "steam" - } - QQC2.TabButton { - text: i18n("Desktop") - width: implicitWidth - onClicked: GamingShell.GameLauncherProvider.sourceFilter = "desktop" - } - QQC2.TabButton { - text: i18n("Waydroid") - width: implicitWidth - onClicked: GamingShell.GameLauncherProvider.sourceFilter = "waydroid" - } - QQC2.TabButton { - text: "Lutris" - width: implicitWidth - onClicked: GamingShell.GameLauncherProvider.sourceFilter = "lutris" - } - QQC2.TabButton { - text: "Heroic" - width: implicitWidth - onClicked: GamingShell.GameLauncherProvider.sourceFilter = "heroic" + Repeater { + model: { + var tabs = [ + {label: i18n("All"), filter: ""}, + {label: i18n("Desktop"), filter: "desktop"}, + {label: i18n("Waydroid"),filter: "waydroid"} + ] + if (GamingShell.GameLauncherProvider.steamAvailable) + tabs.splice(1, 0, {label: "Steam", filter: "steam"}) + if (GamingShell.GameLauncherProvider.lutrisAvailable) + tabs.push({label: "Lutris", filter: "lutris"}) + if (GamingShell.GameLauncherProvider.heroicAvailable) + tabs.push({label: "Heroic", filter: "heroic"}) + return tabs + } + QQC2.TabButton { + text: modelData.label + width: implicitWidth + onClicked: GamingShell.GameLauncherProvider.sourceFilter = modelData.filter + } } } }