diff options
author | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2017-08-13 11:57:06 +0200 |
---|---|---|
committer | Holger Freyther <holger+qt@freyther.de> | 2017-09-12 06:17:11 +0000 |
commit | e9dc7f1db47f5b59d4bf85bc5c8971c2df1dc807 (patch) | |
tree | 35746f52c8edd4c1865a1689f351f6869a3b6769 /wayland | |
parent | 1b2ca45e95b06e81c0373f7055f31042edcd5530 (diff) |
democompositor: Keep track of running apps and enforce singleton
Modify the ProcessLauncher to keep track of running apps in the
m_appStates vector. Answer if an AppEntry has a AppState associated
and use it to not launch a second instance of the application. In
the future this could be an attribute of the .apps file.
Change-Id: I19ed2840e0a64eb7f35fba0cb171e1c7fd722b06
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
Diffstat (limited to 'wayland')
-rw-r--r-- | wayland/democompositor/processlauncher.cpp | 52 | ||||
-rw-r--r-- | wayland/democompositor/processlauncher.h | 30 | ||||
-rw-r--r-- | wayland/democompositor/qml/LaunchButton.qml | 5 |
3 files changed, 76 insertions, 11 deletions
diff --git a/wayland/democompositor/processlauncher.cpp b/wayland/democompositor/processlauncher.cpp index 40b3b8b..c8fe15c 100644 --- a/wayland/democompositor/processlauncher.cpp +++ b/wayland/democompositor/processlauncher.cpp @@ -55,6 +55,16 @@ Q_LOGGING_CATEGORY(procs, "launcher.procs") +/* + * Two AppState's are equal if they are managing the same + * QProcess. It is assumed that no AppState survives beyond + * the QProcess. + */ +bool operator==(const AppState& lhs, const AppState& rhs) +{ + return lhs.process == rhs.process; +} + WaylandProcessLauncher::WaylandProcessLauncher(QObject *parent) : QObject(parent) { @@ -64,26 +74,52 @@ WaylandProcessLauncher::~WaylandProcessLauncher() { } +bool WaylandProcessLauncher::isRunning(const AppEntry& entry) const +{ + for (auto state : m_appStates) { + if (state.appEntry.sourceFileName == entry.sourceFileName) { + qCDebug(procs) << "AppEntry associated to a state" << entry.executableName; + return true; + } + } + + qCDebug(procs) << "AppEntry not associated to a state " << entry.executableName; + return false; +} + void WaylandProcessLauncher::launch(const AppEntry &entry) { qCDebug(procs) << "Launching" << entry.executableName; QProcess *process = new QProcess(this); + AppState state{process, entry}; + m_appStates.push_back(state); + /* handle potential errors and life cycle */ connect(process, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), - [process, entry](int exitCode, QProcess::ExitStatus status) { - qCDebug(procs) << "AppEntry finished" << entry.executableName << exitCode << status; - process->deleteLater(); + [state, this](int exitCode, QProcess::ExitStatus status) { + qCDebug(procs) << "AppEntry finished" << state.appEntry.executableName << exitCode << status; + emit appFinished(state, exitCode, status); + m_appStates.removeOne(state); + state.process->deleteLater(); }); connect(process, &QProcess::errorOccurred, - [process, entry](QProcess::ProcessError err) { - qCDebug(procs) << "AppEntry error occurred" << entry.executableName << err; - process->deleteLater(); + [state, this](QProcess::ProcessError err) { + qCDebug(procs) << "AppEntry error occurred" << state.appEntry.executableName << err; + + /* Maybe finished was already emitted. Let's not emit an error after that */ + if (!m_appStates.removeOne(state)) + return; + + if (err == QProcess::FailedToStart || err == QProcess::UnknownError) + emit appNotStarted(state); + state.process->deleteLater(); }); connect(process, &QProcess::started, - [process, entry]() { - qCDebug(procs) << "AppEntry started" << entry.executableName; + [state, this]() { + qCDebug(procs) << "AppEntry started" << state.appEntry.executableName; + emit appStarted(state); }); if (!entry.executablePath.isNull()) { diff --git a/wayland/democompositor/processlauncher.h b/wayland/democompositor/processlauncher.h index 092c0a3..84f9cb8 100644 --- a/wayland/democompositor/processlauncher.h +++ b/wayland/democompositor/processlauncher.h @@ -51,13 +51,27 @@ #ifndef PROCESSLAUNCHER_H #define PROCESSLAUNCHER_H +#include "apps/appentry.h" + #include <QObject> +#include <QProcess> #include <QLoggingCategory> -class AppEntry; - Q_DECLARE_LOGGING_CATEGORY(procs) +/** + * Transient class. Do not keep AppState beyond the + * finished signal. + */ +class AppState { + Q_GADGET + Q_PROPERTY(QProcess *process MEMBER process CONSTANT) + Q_PROPERTY(AppEntry appEntry MEMBER appEntry CONSTANT) +public: + QProcess *process; + AppEntry appEntry; +}; + class WaylandProcessLauncher : public QObject { Q_OBJECT @@ -66,6 +80,18 @@ public: explicit WaylandProcessLauncher(QObject *parent = 0); ~WaylandProcessLauncher(); Q_INVOKABLE void launch(const AppEntry &entry); + + Q_INVOKABLE bool isRunning(const AppEntry& entry) const; + +Q_SIGNALS: + void appStarted(const AppState &appState); + void appFinished(const AppState &appState, int exitCode, QProcess::ExitStatus exitStatus); + void appNotStarted(const AppState& appState); + +private: + QVector<AppState> m_appStates; }; +Q_DECLARE_METATYPE(AppState) + #endif // PROCESSLAUNCHER_H diff --git a/wayland/democompositor/qml/LaunchButton.qml b/wayland/democompositor/qml/LaunchButton.qml index 2d3801a..80a057a 100644 --- a/wayland/democompositor/qml/LaunchButton.qml +++ b/wayland/democompositor/qml/LaunchButton.qml @@ -57,5 +57,8 @@ MyButton { text.maximumLineCount: 1 iconSize: 32 - onTriggered: launcher.launch(appEntry) + onTriggered: { + if (!launcher.isRunning(appEntry)) + launcher.launch(appEntry) + } } |