mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2025-07-01 23:35:55 +00:00
Add support for selecting an app to launch directly
This commit is contained in:
parent
d7ca3801be
commit
72182c7caa
@ -5,6 +5,7 @@
|
|||||||
#define SER_APPHDR "hdr"
|
#define SER_APPHDR "hdr"
|
||||||
#define SER_APPCOLLECTOR "appcollector"
|
#define SER_APPCOLLECTOR "appcollector"
|
||||||
#define SER_HIDDEN "hidden"
|
#define SER_HIDDEN "hidden"
|
||||||
|
#define SER_DIRECTLAUNCH "directlaunch"
|
||||||
|
|
||||||
NvApp::NvApp(QSettings& settings)
|
NvApp::NvApp(QSettings& settings)
|
||||||
{
|
{
|
||||||
@ -13,6 +14,7 @@ NvApp::NvApp(QSettings& settings)
|
|||||||
hdrSupported = settings.value(SER_APPHDR).toBool();
|
hdrSupported = settings.value(SER_APPHDR).toBool();
|
||||||
isAppCollectorGame = settings.value(SER_APPCOLLECTOR).toBool();
|
isAppCollectorGame = settings.value(SER_APPCOLLECTOR).toBool();
|
||||||
hidden = settings.value(SER_HIDDEN).toBool();
|
hidden = settings.value(SER_HIDDEN).toBool();
|
||||||
|
directLaunch = settings.value(SER_DIRECTLAUNCH).toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NvApp::serialize(QSettings& settings) const
|
void NvApp::serialize(QSettings& settings) const
|
||||||
@ -22,4 +24,5 @@ void NvApp::serialize(QSettings& settings) const
|
|||||||
settings.setValue(SER_APPHDR, hdrSupported);
|
settings.setValue(SER_APPHDR, hdrSupported);
|
||||||
settings.setValue(SER_APPCOLLECTOR, isAppCollectorGame);
|
settings.setValue(SER_APPCOLLECTOR, isAppCollectorGame);
|
||||||
settings.setValue(SER_HIDDEN, hidden);
|
settings.setValue(SER_HIDDEN, hidden);
|
||||||
|
settings.setValue(SER_DIRECTLAUNCH, directLaunch);
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ public:
|
|||||||
name == other.name &&
|
name == other.name &&
|
||||||
hdrSupported == other.hdrSupported &&
|
hdrSupported == other.hdrSupported &&
|
||||||
isAppCollectorGame == other.isAppCollectorGame &&
|
isAppCollectorGame == other.isAppCollectorGame &&
|
||||||
hidden == other.hidden;
|
hidden == other.hidden &&
|
||||||
|
directLaunch == other.directLaunch;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const NvApp& other) const
|
bool operator!=(const NvApp& other) const
|
||||||
@ -35,6 +36,7 @@ public:
|
|||||||
bool hdrSupported = false;
|
bool hdrSupported = false;
|
||||||
bool isAppCollectorGame = false;
|
bool isAppCollectorGame = false;
|
||||||
bool hidden = false;
|
bool hidden = false;
|
||||||
|
bool directLaunch = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(NvApp)
|
Q_DECLARE_METATYPE(NvApp)
|
||||||
|
@ -317,6 +317,7 @@ bool NvComputer::updateAppList(QVector<NvApp> newAppList) {
|
|||||||
for (NvApp& newApp : newAppList) {
|
for (NvApp& newApp : newAppList) {
|
||||||
if (existingApp.id == newApp.id) {
|
if (existingApp.id == newApp.id) {
|
||||||
newApp.hidden = existingApp.hidden;
|
newApp.hidden = existingApp.hidden;
|
||||||
|
newApp.directLaunch = existingApp.directLaunch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ CenteredGridView {
|
|||||||
property AppModel appModel : createModel()
|
property AppModel appModel : createModel()
|
||||||
property bool activated
|
property bool activated
|
||||||
property bool showHiddenGames
|
property bool showHiddenGames
|
||||||
|
property bool showGames
|
||||||
|
|
||||||
id: appGrid
|
id: appGrid
|
||||||
focus: true
|
focus: true
|
||||||
@ -39,6 +40,19 @@ CenteredGridView {
|
|||||||
if (currentIndex == -1 && SdlGamepadKeyNavigation.getConnectedGamepads() > 0) {
|
if (currentIndex == -1 && SdlGamepadKeyNavigation.getConnectedGamepads() > 0) {
|
||||||
currentIndex = 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: {
|
StackView.onDeactivating: {
|
||||||
@ -112,7 +126,7 @@ CenteredGridView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
launchOrResumeSelectedApp()
|
launchOrResumeSelectedApp(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
ToolTip.text: qsTr("Resume Game")
|
ToolTip.text: qsTr("Resume Game")
|
||||||
@ -167,15 +181,18 @@ CenteredGridView {
|
|||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
|
|
||||||
function launchOrResumeSelectedApp()
|
function launchOrResumeSelectedApp(quitExistingApp)
|
||||||
{
|
{
|
||||||
var runningId = appModel.getRunningAppId()
|
var runningId = appModel.getRunningAppId()
|
||||||
if (runningId !== 0 && runningId !== model.appid) {
|
if (runningId !== 0 && runningId !== model.appid) {
|
||||||
quitAppDialog.appName = appModel.getRunningAppName()
|
if (quitExistingApp) {
|
||||||
quitAppDialog.segueToStream = true
|
quitAppDialog.appName = appModel.getRunningAppName()
|
||||||
quitAppDialog.nextAppName = model.name
|
quitAppDialog.segueToStream = true
|
||||||
quitAppDialog.nextAppIndex = index
|
quitAppDialog.nextAppName = model.name
|
||||||
quitAppDialog.open()
|
quitAppDialog.nextAppIndex = index
|
||||||
|
quitAppDialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +207,7 @@ CenteredGridView {
|
|||||||
// will handle starting the game and clicks on the box art will
|
// will handle starting the game and clicks on the box art will
|
||||||
// be ignored.
|
// be ignored.
|
||||||
if (!model.running) {
|
if (!model.running) {
|
||||||
launchOrResumeSelectedApp()
|
launchOrResumeSelectedApp(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,7 +257,7 @@ CenteredGridView {
|
|||||||
NavigableMenuItem {
|
NavigableMenuItem {
|
||||||
parentMenu: appContextMenu
|
parentMenu: appContextMenu
|
||||||
text: model.running ? qsTr("Resume Game") : qsTr("Launch Game")
|
text: model.running ? qsTr("Resume Game") : qsTr("Launch Game")
|
||||||
onTriggered: launchOrResumeSelectedApp()
|
onTriggered: launchOrResumeSelectedApp(true)
|
||||||
}
|
}
|
||||||
NavigableMenuItem {
|
NavigableMenuItem {
|
||||||
parentMenu: appContextMenu
|
parentMenu: appContextMenu
|
||||||
@ -256,6 +273,19 @@ CenteredGridView {
|
|||||||
onTriggered: appModel.setAppHidden(model.index, !model.hidden)
|
onTriggered: appModel.setAppHidden(model.index, !model.hidden)
|
||||||
visible: !model.running || 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ CenteredGridView {
|
|||||||
text: qsTr("View Apps")
|
text: qsTr("View Apps")
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
var component = Qt.createComponent("AppView.qml")
|
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)
|
stackView.push(appView)
|
||||||
}
|
}
|
||||||
visible: model.online && model.paired
|
visible: model.online && model.paired
|
||||||
|
@ -47,6 +47,17 @@ Session* AppModel::createSessionForApp(int appIndex)
|
|||||||
return new Session(m_Computer, app);
|
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
|
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
|
// 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;
|
return app.hidden;
|
||||||
case AppIdRole:
|
case AppIdRole:
|
||||||
return app.id;
|
return app.id;
|
||||||
|
case DirectLaunchRole:
|
||||||
|
return app.directLaunch;
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@ -92,6 +105,7 @@ QHash<int, QByteArray> AppModel::roleNames() const
|
|||||||
names[BoxArtRole] = "boxart";
|
names[BoxArtRole] = "boxart";
|
||||||
names[HiddenRole] = "hidden";
|
names[HiddenRole] = "hidden";
|
||||||
names[AppIdRole] = "appid";
|
names[AppIdRole] = "appid";
|
||||||
|
names[DirectLaunchRole] = "directLaunch";
|
||||||
|
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
@ -207,6 +221,32 @@ void AppModel::setAppHidden(int appIndex, bool hidden)
|
|||||||
m_ComputerManager->clientSideAttributeUpdated(m_Computer);
|
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)
|
void AppModel::handleComputerStateChanged(NvComputer* computer)
|
||||||
{
|
{
|
||||||
// Ignore updates for computers that aren't ours
|
// Ignore updates for computers that aren't ours
|
||||||
|
@ -17,6 +17,7 @@ class AppModel : public QAbstractListModel
|
|||||||
BoxArtRole,
|
BoxArtRole,
|
||||||
HiddenRole,
|
HiddenRole,
|
||||||
AppIdRole,
|
AppIdRole,
|
||||||
|
DirectLaunchRole
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -27,6 +28,8 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE Session* createSessionForApp(int appIndex);
|
Q_INVOKABLE Session* createSessionForApp(int appIndex);
|
||||||
|
|
||||||
|
Q_INVOKABLE int getDirectLaunchAppIndex();
|
||||||
|
|
||||||
Q_INVOKABLE int getRunningAppId();
|
Q_INVOKABLE int getRunningAppId();
|
||||||
|
|
||||||
Q_INVOKABLE QString getRunningAppName();
|
Q_INVOKABLE QString getRunningAppName();
|
||||||
@ -35,6 +38,8 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE void setAppHidden(int appIndex, bool hidden);
|
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;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent) const override;
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user