From 72182c7caaeb875f483001a52c220927143e7c88 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 23 Nov 2020 21:38:22 -0600 Subject: [PATCH] Add support for selecting an app to launch directly --- app/backend/nvapp.cpp | 3 +++ app/backend/nvapp.h | 4 +++- app/backend/nvcomputer.cpp | 1 + app/gui/AppView.qml | 48 +++++++++++++++++++++++++++++++------- app/gui/PcView.qml | 2 +- app/gui/appmodel.cpp | 40 +++++++++++++++++++++++++++++++ app/gui/appmodel.h | 5 ++++ 7 files changed, 92 insertions(+), 11 deletions(-) diff --git a/app/backend/nvapp.cpp b/app/backend/nvapp.cpp index e3f866f2..c1f3e064 100644 --- a/app/backend/nvapp.cpp +++ b/app/backend/nvapp.cpp @@ -5,6 +5,7 @@ #define SER_APPHDR "hdr" #define SER_APPCOLLECTOR "appcollector" #define SER_HIDDEN "hidden" +#define SER_DIRECTLAUNCH "directlaunch" NvApp::NvApp(QSettings& settings) { @@ -13,6 +14,7 @@ NvApp::NvApp(QSettings& settings) hdrSupported = settings.value(SER_APPHDR).toBool(); isAppCollectorGame = settings.value(SER_APPCOLLECTOR).toBool(); hidden = settings.value(SER_HIDDEN).toBool(); + directLaunch = settings.value(SER_DIRECTLAUNCH).toBool(); } void NvApp::serialize(QSettings& settings) const @@ -22,4 +24,5 @@ void NvApp::serialize(QSettings& settings) const settings.setValue(SER_APPHDR, hdrSupported); settings.setValue(SER_APPCOLLECTOR, isAppCollectorGame); settings.setValue(SER_HIDDEN, hidden); + settings.setValue(SER_DIRECTLAUNCH, directLaunch); } diff --git a/app/backend/nvapp.h b/app/backend/nvapp.h index ef1c9a9b..bf51db63 100644 --- a/app/backend/nvapp.h +++ b/app/backend/nvapp.h @@ -14,7 +14,8 @@ public: name == other.name && hdrSupported == other.hdrSupported && isAppCollectorGame == other.isAppCollectorGame && - hidden == other.hidden; + hidden == other.hidden && + directLaunch == other.directLaunch; } bool operator!=(const NvApp& other) const @@ -35,6 +36,7 @@ public: bool hdrSupported = false; bool isAppCollectorGame = false; bool hidden = false; + bool directLaunch = false; }; Q_DECLARE_METATYPE(NvApp) diff --git a/app/backend/nvcomputer.cpp b/app/backend/nvcomputer.cpp index 3c0ffc8b..9bd37bbe 100644 --- a/app/backend/nvcomputer.cpp +++ b/app/backend/nvcomputer.cpp @@ -317,6 +317,7 @@ bool NvComputer::updateAppList(QVector newAppList) { for (NvApp& newApp : newAppList) { if (existingApp.id == newApp.id) { newApp.hidden = existingApp.hidden; + newApp.directLaunch = existingApp.directLaunch; } } } diff --git a/app/gui/AppView.qml b/app/gui/AppView.qml index bcecd8c7..233a5bd3 100644 --- a/app/gui/AppView.qml +++ b/app/gui/AppView.qml @@ -10,6 +10,7 @@ CenteredGridView { property AppModel appModel : createModel() property bool activated property bool showHiddenGames + property bool showGames id: appGrid focus: true @@ -39,6 +40,19 @@ CenteredGridView { if (currentIndex == -1 && SdlGamepadKeyNavigation.getConnectedGamepads() > 0) { currentIndex = 0 } + + if (!showGames && !showHiddenGames) { + // Check if there's a direct launch app + var directLaunchAppIndex = model.getDirectLaunchAppIndex(); + if (directLaunchAppIndex >= 0) { + // Start the direct launch app if nothing else is running + currentIndex = directLaunchAppIndex + currentItem.launchOrResumeSelectedApp(false) + + // Set showGames so we will not loop when the stream ends + showGames = true + } + } } StackView.onDeactivating: { @@ -112,7 +126,7 @@ CenteredGridView { } onClicked: { - launchOrResumeSelectedApp() + launchOrResumeSelectedApp(true) } ToolTip.text: qsTr("Resume Game") @@ -167,15 +181,18 @@ CenteredGridView { elide: Text.ElideRight } - function launchOrResumeSelectedApp() + function launchOrResumeSelectedApp(quitExistingApp) { var runningId = appModel.getRunningAppId() if (runningId !== 0 && runningId !== model.appid) { - quitAppDialog.appName = appModel.getRunningAppName() - quitAppDialog.segueToStream = true - quitAppDialog.nextAppName = model.name - quitAppDialog.nextAppIndex = index - quitAppDialog.open() + if (quitExistingApp) { + quitAppDialog.appName = appModel.getRunningAppName() + quitAppDialog.segueToStream = true + quitAppDialog.nextAppName = model.name + quitAppDialog.nextAppIndex = index + quitAppDialog.open() + } + return } @@ -190,7 +207,7 @@ CenteredGridView { // will handle starting the game and clicks on the box art will // be ignored. if (!model.running) { - launchOrResumeSelectedApp() + launchOrResumeSelectedApp(true) } } @@ -240,7 +257,7 @@ CenteredGridView { NavigableMenuItem { parentMenu: appContextMenu text: model.running ? qsTr("Resume Game") : qsTr("Launch Game") - onTriggered: launchOrResumeSelectedApp() + onTriggered: launchOrResumeSelectedApp(true) } NavigableMenuItem { parentMenu: appContextMenu @@ -256,6 +273,19 @@ CenteredGridView { onTriggered: appModel.setAppHidden(model.index, !model.hidden) visible: !model.running || model.hidden } + NavigableMenuItem { + parentMenu: appContextMenu + checkable: true + checked: model.directLaunch + text: qsTr("Direct Launch") + onTriggered: appModel.setAppDirectLaunch(model.index, !model.directLaunch) + visible: !model.hidden + + ToolTip.text: qsTr("Launch this app immediately when the host is selected, bypassing the app selection grid.") + ToolTip.delay: 1000 + ToolTip.timeout: 3000 + ToolTip.visible: hovered + } } } diff --git a/app/gui/PcView.qml b/app/gui/PcView.qml index 2521069f..4a8b60b7 100644 --- a/app/gui/PcView.qml +++ b/app/gui/PcView.qml @@ -167,7 +167,7 @@ CenteredGridView { text: qsTr("View Apps") onTriggered: { var component = Qt.createComponent("AppView.qml") - var appView = component.createObject(stackView, {"computerIndex": index, "objectName": model.name}) + var appView = component.createObject(stackView, {"computerIndex": index, "objectName": model.name, "showGames": true}) stackView.push(appView) } visible: model.online && model.paired diff --git a/app/gui/appmodel.cpp b/app/gui/appmodel.cpp index 23e48115..67630773 100644 --- a/app/gui/appmodel.cpp +++ b/app/gui/appmodel.cpp @@ -47,6 +47,17 @@ Session* AppModel::createSessionForApp(int appIndex) return new Session(m_Computer, app); } +int AppModel::getDirectLaunchAppIndex() +{ + for (int i = 0; i < m_AllApps.count(); i++) { + if (m_VisibleApps[i].directLaunch) { + return i; + } + } + + return -1; +} + int AppModel::rowCount(const QModelIndex &parent) const { // For list models only the root node (an invalid parent) should return the list's size. For all @@ -78,6 +89,8 @@ QVariant AppModel::data(const QModelIndex &index, int role) const return app.hidden; case AppIdRole: return app.id; + case DirectLaunchRole: + return app.directLaunch; default: return QVariant(); } @@ -92,6 +105,7 @@ QHash AppModel::roleNames() const names[BoxArtRole] = "boxart"; names[HiddenRole] = "hidden"; names[AppIdRole] = "appid"; + names[DirectLaunchRole] = "directLaunch"; return names; } @@ -207,6 +221,32 @@ void AppModel::setAppHidden(int appIndex, bool hidden) m_ComputerManager->clientSideAttributeUpdated(m_Computer); } +void AppModel::setAppDirectLaunch(int appIndex, bool directLaunch) +{ + Q_ASSERT(appIndex < m_VisibleApps.count()); + int appId = m_VisibleApps.at(appIndex).id; + + { + QWriteLocker lock(&m_Computer->lock); + + for (NvApp& app : m_Computer->appList) { + if (directLaunch) { + // We must clear direct launch from all other apps + // to set it on the new app. + app.directLaunch = app.id == appId; + } + else if (app.id == appId) { + // If we're clearing direct launch, we're done once we + // find our matching app ID. + app.directLaunch = false; + break; + } + } + } + + m_ComputerManager->clientSideAttributeUpdated(m_Computer); +} + void AppModel::handleComputerStateChanged(NvComputer* computer) { // Ignore updates for computers that aren't ours diff --git a/app/gui/appmodel.h b/app/gui/appmodel.h index bf072361..37717926 100644 --- a/app/gui/appmodel.h +++ b/app/gui/appmodel.h @@ -17,6 +17,7 @@ class AppModel : public QAbstractListModel BoxArtRole, HiddenRole, AppIdRole, + DirectLaunchRole }; public: @@ -27,6 +28,8 @@ public: Q_INVOKABLE Session* createSessionForApp(int appIndex); + Q_INVOKABLE int getDirectLaunchAppIndex(); + Q_INVOKABLE int getRunningAppId(); Q_INVOKABLE QString getRunningAppName(); @@ -35,6 +38,8 @@ public: Q_INVOKABLE void setAppHidden(int appIndex, bool hidden); + Q_INVOKABLE void setAppDirectLaunch(int appIndex, bool directLaunch); + QVariant data(const QModelIndex &index, int role) const override; int rowCount(const QModelIndex &parent) const override;