mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-06-11 08:57:21 +00:00
Steam, Lutris, and Heroic filter tabs in the Game Center are now only shown when those launchers are detected on the system. Detection checks the native executable, known Flatpak data directories, and standard data paths. The tab bar shrinks accordingly.
158 lines
6.1 KiB
C++
158 lines
6.1 KiB
C++
// SPDX-FileCopyrightText: 2026 Marco Allegretti
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
#pragma once
|
|
|
|
#include <QAbstractListModel>
|
|
#include <QDateTime>
|
|
#include <QList>
|
|
#include <QSet>
|
|
#include <QString>
|
|
#include <QTimer>
|
|
#include <QVariantMap>
|
|
#include <qqmlregistration.h>
|
|
|
|
#include <KConfigWatcher>
|
|
#include <KSharedConfig>
|
|
|
|
class GameLauncherProvider : public QAbstractListModel
|
|
{
|
|
Q_OBJECT
|
|
QML_ELEMENT
|
|
QML_SINGLETON
|
|
|
|
Q_PROPERTY(int count READ count NOTIFY countChanged)
|
|
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
|
|
Q_PROPERTY(QString filterString READ filterString WRITE setFilterString NOTIFY filterStringChanged)
|
|
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)
|
|
Q_PROPERTY(QString lastLaunchError READ lastLaunchError NOTIFY lastLaunchErrorChanged)
|
|
|
|
public:
|
|
explicit GameLauncherProvider(QObject *parent = nullptr);
|
|
|
|
enum Roles {
|
|
NameRole = Qt::UserRole + 1,
|
|
IconRole,
|
|
SourceRole, // "desktop", "waydroid", "steam", "flatpak"
|
|
StorageIdRole, // .desktop file name or launch URI
|
|
LaunchCommandRole,
|
|
LaunchMethodRole,
|
|
ArtworkRole, // path to banner/grid image (empty if none)
|
|
LastPlayedTextRole,
|
|
PinnedRole,
|
|
};
|
|
Q_ENUM(Roles)
|
|
|
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
|
QVariant data(const QModelIndex &index, int role) const override;
|
|
QHash<int, QByteArray> roleNames() const override;
|
|
|
|
int count() const;
|
|
bool loading() const;
|
|
QString filterString() const;
|
|
void setFilterString(const QString &filter);
|
|
QString sourceFilter() const;
|
|
void setSourceFilter(const QString &source);
|
|
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;
|
|
QString pendingLaunchName() const;
|
|
QString lastLaunchError() const;
|
|
|
|
Q_INVOKABLE void refresh();
|
|
Q_INVOKABLE void launch(int index);
|
|
Q_INVOKABLE void launchByStorageId(const QString &storageId);
|
|
Q_INVOKABLE QVariantMap gameDetails(const QString &storageId) const;
|
|
Q_INVOKABLE bool openSourceApp(const QString &source);
|
|
Q_INVOKABLE void clearLastPlayed(const QString &storageId);
|
|
Q_INVOKABLE QVariantList recentGames(int limit = 5) const;
|
|
Q_INVOKABLE void clearPendingLaunch();
|
|
Q_INVOKABLE void clearLastLaunchError();
|
|
Q_INVOKABLE void togglePin(const QString &storageId);
|
|
Q_INVOKABLE int perGameFpsLimit(const QString &storageId) const;
|
|
Q_INVOKABLE void setPerGameFpsLimit(const QString &storageId, int limit);
|
|
Q_INVOKABLE int perGameOverlayState(const QString &storageId) const;
|
|
Q_INVOKABLE void setPerGameOverlayState(const QString &storageId, int state);
|
|
|
|
Q_SIGNALS:
|
|
void countChanged();
|
|
void loadingChanged();
|
|
void filterStringChanged();
|
|
void sourceFilterChanged();
|
|
void overlayEnabledChanged();
|
|
void mangohudAvailableChanged();
|
|
void launcherAvailabilityChanged();
|
|
void fpsLimitChanged();
|
|
void launchPendingChanged();
|
|
void lastLaunchErrorChanged();
|
|
void gameLaunched(const QString &name);
|
|
void gameLaunchFailed(const QString &name, const QString &error);
|
|
void recentGamesChanged();
|
|
|
|
private:
|
|
struct GameEntry {
|
|
QString name;
|
|
QString icon;
|
|
QString source;
|
|
QString storageId;
|
|
QString launchCommand;
|
|
QString artwork;
|
|
QDateTime lastPlayed;
|
|
};
|
|
|
|
void loadDesktopGames();
|
|
void loadSteamGames();
|
|
void loadLutrisGames();
|
|
void loadHeroicGames();
|
|
void deduplicateGames();
|
|
void loadRecentTimestamps();
|
|
void saveRecentTimestamp(const QString &storageId, const QDateTime &when);
|
|
void applyFilter();
|
|
void launchEntry(GameEntry &entry);
|
|
bool launchWithMangohud(const QString &program, const QStringList &args, bool overlayEnabled, int fpsLimit, qint64 *pid = nullptr);
|
|
QString launchMethodForEntry(const GameEntry &entry) const;
|
|
QString formatLastPlayed(const QDateTime &when) const;
|
|
// Returns the current m_allGames index for the storage id.
|
|
// Callers must re-lookup after any mutation that can rebuild or reorder the list.
|
|
int findEntryIndexByStorageId(const QString &storageId) const;
|
|
void markLaunchSucceeded(const QString &storageId, const QString &name);
|
|
void markLaunchFailed(const QString &name, const QString &error);
|
|
void setPendingLaunch(const QString &name);
|
|
void loadPinnedGames();
|
|
|
|
QList<GameEntry> m_allGames;
|
|
QList<GameEntry> m_games; // filtered view
|
|
QString m_filterString;
|
|
QString m_sourceFilter; // empty = all, or a specific source such as "desktop" or "waydroid"
|
|
KSharedConfigPtr m_config;
|
|
bool m_loading = false;
|
|
bool m_overlayEnabled = false;
|
|
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<QString> m_pinnedGames;
|
|
bool m_launchPending = false;
|
|
QString m_pendingLaunchName;
|
|
QString m_lastLaunchError;
|
|
QTimer m_pendingLaunchTimer;
|
|
KConfigWatcher::Ptr m_configWatcher;
|
|
};
|