Simplify app quitting implementation a bit

This commit is contained in:
Cameron Gutman 2018-12-05 19:49:06 -08:00
parent 2eee839eaa
commit 5029c855f0
6 changed files with 71 additions and 59 deletions

View File

@ -1,7 +1,6 @@
#include "computermanager.h" #include "computermanager.h"
#include "nvhttp.h" #include "nvhttp.h"
#include "settings/streamingpreferences.h" #include "settings/streamingpreferences.h"
#include "streaming/session.h"
#include <Limelight.h> #include <Limelight.h>
#include <QtEndian> #include <QtEndian>
@ -479,11 +478,6 @@ void ComputerManager::quitRunningApp(NvComputer* computer)
QThreadPool::globalInstance()->start(quit); QThreadPool::globalInstance()->start(quit);
} }
void ComputerManager::quitRunningApp(Session *session)
{
quitRunningApp(session->getComputer());
}
void ComputerManager::stopPollingAsync() void ComputerManager::stopPollingAsync()
{ {
QWriteLocker lock(&m_Lock); QWriteLocker lock(&m_Lock);

View File

@ -14,8 +14,6 @@
#include <QSettings> #include <QSettings>
#include <QRunnable> #include <QRunnable>
class Session;
class MdnsPendingComputer : public QObject class MdnsPendingComputer : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -74,7 +72,6 @@ public:
void pairHost(NvComputer* computer, QString pin); void pairHost(NvComputer* computer, QString pin);
void quitRunningApp(NvComputer* computer); void quitRunningApp(NvComputer* computer);
Q_INVOKABLE void quitRunningApp(Session* session);
QVector<NvComputer*> getComputers(); QVector<NvComputer*> getComputers();

View File

@ -57,13 +57,8 @@ NvHTTP::getCurrentGame(QString serverInfo)
// GFE 2.8 started keeping currentgame set to the last game played. As a result, it no longer // GFE 2.8 started keeping currentgame set to the last game played. As a result, it no longer
// has the semantics that its name would indicate. To contain the effects of this change as much // has the semantics that its name would indicate. To contain the effects of this change as much
// as possible, we'll force the current game to zero if the server isn't in a streaming session. // as possible, we'll force the current game to zero if the server isn't in a streaming session.
//
// However, current game info must be available also in other states than just _SERVER_BUSY as
// it is required for quitting currently running app. Quitting app occurs at end of stream if
// configured so. At that point the server state may be in some other state than _SERVER_BUSY
// for a short while, but that must not prevent quitting of the app.
QString serverState = getXmlString(serverInfo, "state"); QString serverState = getXmlString(serverInfo, "state");
if (serverState != nullptr && !serverState.endsWith("_SERVER_AVAILABLE")) if (serverState != nullptr && serverState.endsWith("_SERVER_BUSY"))
{ {
return getXmlString(serverInfo, "currentgame").toInt(); return getXmlString(serverInfo, "currentgame").toInt();
} }

View File

@ -12,7 +12,6 @@ Item {
property string appName property string appName
property string stageText : "Starting " + appName + "..." property string stageText : "Starting " + appName + "..."
property bool quitAfter : false property bool quitAfter : false
property bool sessionLaunched : false
anchors.fill: parent anchors.fill: parent
@ -61,17 +60,27 @@ Item {
toast.visible = true toast.visible = true
} }
function streamingFinished() { function quitStarting()
{
// Avoid the push transition animation
var component = Qt.createComponent("QuitSegue.qml")
stackView.replace(stackView.currentItem, component.createObject(stackView, {"appName": appName}), StackView.Immediate)
// Show the Qt window again to show quit segue
window.visible = true
}
function sessionFinished()
{
if (quitAfter) { if (quitAfter) {
window.visible = false
Qt.quit() Qt.quit()
} else { } else {
// Show the Qt window again after streaming
window.visible = true
// Exit this view // Exit this view
stackView.pop() stackView.pop()
// Show the Qt window again after streaming
window.visible = true
// Display any launch errors. We do this after // Display any launch errors. We do this after
// the Qt UI is visible again to prevent losing // the Qt UI is visible again to prevent losing
// focus on the dialog which would impact gamepad // focus on the dialog which would impact gamepad
@ -91,12 +100,6 @@ Item {
onVisibleChanged: { onVisibleChanged: {
if (visible) { if (visible) {
// Prevent session restart after execution returns from QuitSegue
if (sessionLaunched) {
return
}
sessionLaunched = true
// Hide the toolbar before we start loading // Hide the toolbar before we start loading
toolBar.visible = false toolBar.visible = false
@ -114,21 +117,11 @@ Item {
session.connectionStarted.connect(connectionStarted) session.connectionStarted.connect(connectionStarted)
session.displayLaunchError.connect(displayLaunchError) session.displayLaunchError.connect(displayLaunchError)
session.displayLaunchWarning.connect(displayLaunchWarning) session.displayLaunchWarning.connect(displayLaunchWarning)
session.quitStarting.connect(quitStarting)
session.sessionFinished.connect(sessionFinished)
// Run the streaming session to completion // Run the streaming session to completion
session.exec(Screen.virtualX, Screen.virtualY); session.exec(Screen.virtualX, Screen.virtualY)
if (!errorDialog.text && session.shouldQuitAppAfter()) {
// Show the Qt window again to show quit segue
window.visible = true
var component = Qt.createComponent("QuitSegue.qml")
stackView.push(component.createObject(stackView, {"appName": appName}))
// Quit app
ComputerManager.quitAppCompleted.connect(streamingFinished)
ComputerManager.quitRunningApp(session)
} else {
streamingFinished()
}
} }
else if (!quitAfter) { else if (!quitAfter) {
// Show the toolbar again when we become hidden // Show the toolbar again when we become hidden

View File

@ -275,16 +275,6 @@ int Session::getDecoderCapabilities(StreamingPreferences::VideoDecoderSelection
return caps; return caps;
} }
NvComputer *Session::getComputer() const
{
return m_Computer;
}
bool Session::shouldQuitAppAfter() const
{
return m_Preferences->quitAppAfter;
}
Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *preferences) Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *preferences)
: m_Preferences(preferences ? preferences : new StreamingPreferences(this)), : m_Preferences(preferences ? preferences : new StreamingPreferences(this)),
m_Computer(computer), m_Computer(computer),
@ -303,6 +293,14 @@ Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *prefere
{ {
} }
Session::~Session()
{
// Acquire session semaphore to ensure all cleanup is done before the destructor returns
// and the object is deallocated.
s_ActiveSessionSemaphore.acquire();
s_ActiveSessionSemaphore.release();
}
void Session::initialize() void Session::initialize()
{ {
qInfo() << "Server GPU:" << m_Computer->gpuModel; qInfo() << "Server GPU:" << m_Computer->gpuModel;
@ -561,15 +559,48 @@ bool Session::validateLaunch()
class DeferredSessionCleanupTask : public QRunnable class DeferredSessionCleanupTask : public QRunnable
{ {
void run() override public:
{ DeferredSessionCleanupTask(Session* session) :
// Finish cleanup of the connection state m_Session(session) {}
LiStopConnection();
private:
virtual ~DeferredSessionCleanupTask() override
{
// Allow another session to start now that we're cleaned up // Allow another session to start now that we're cleaned up
Session::s_ActiveSession = nullptr; Session::s_ActiveSession = nullptr;
Session::s_ActiveSessionSemaphore.release(); Session::s_ActiveSessionSemaphore.release();
} }
void run() override
{
// Notify the UI
if (!m_Session->m_Preferences->quitAppAfter) {
emit m_Session->sessionFinished();
}
else {
emit m_Session->quitStarting();
}
// Finish cleanup of the connection state
LiStopConnection();
// Perform a best-effort app quit
if (m_Session->m_Preferences->quitAppAfter) {
NvHTTP http(m_Session->m_Computer->activeAddress);
// Logging is already done inside NvHTTP
try {
http.quitApp();
} catch (const GfeHttpResponseException&) {
} catch (const QtNetworkReplyException&) {
}
// Session is finished now
emit m_Session->sessionFinished();
}
}
Session* m_Session;
}; };
void Session::getWindowDimensions(int& x, int& y, void Session::getWindowDimensions(int& x, int& y,
@ -1162,6 +1193,6 @@ DispatchDeferredCleanup:
// Cleanup can take a while, so dispatch it to a worker thread. // Cleanup can take a while, so dispatch it to a worker thread.
// When it is complete, it will release our s_ActiveSessionSemaphore // When it is complete, it will release our s_ActiveSessionSemaphore
// reference. // reference.
QThreadPool::globalInstance()->start(new DeferredSessionCleanupTask()); QThreadPool::globalInstance()->start(new DeferredSessionCleanupTask(this));
} }

View File

@ -20,6 +20,8 @@ class Session : public QObject
public: public:
explicit Session(NvComputer* computer, NvApp& app, StreamingPreferences *preferences = nullptr); explicit Session(NvComputer* computer, NvApp& app, StreamingPreferences *preferences = nullptr);
virtual ~Session();
Q_INVOKABLE void exec(int displayOriginX, int displayOriginY); Q_INVOKABLE void exec(int displayOriginX, int displayOriginY);
static static
@ -30,10 +32,6 @@ public:
int getDecoderCapabilities(StreamingPreferences::VideoDecoderSelection vds, int getDecoderCapabilities(StreamingPreferences::VideoDecoderSelection vds,
int videoFormat, int width, int height, int frameRate); int videoFormat, int width, int height, int frameRate);
NvComputer* getComputer() const;
Q_INVOKABLE bool shouldQuitAppAfter() const;
signals: signals:
void stageStarting(QString stage); void stageStarting(QString stage);
@ -45,6 +43,10 @@ signals:
void displayLaunchWarning(QString text); void displayLaunchWarning(QString text);
void quitStarting();
void sessionFinished();
private: private:
void initialize(); void initialize();