summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <holger@moiji-mobile.com>2017-08-13 11:57:06 +0200
committerHolger Freyther <holger+qt@freyther.de>2017-09-12 06:17:11 +0000
commite9dc7f1db47f5b59d4bf85bc5c8971c2df1dc807 (patch)
tree35746f52c8edd4c1865a1689f351f6869a3b6769
parent1b2ca45e95b06e81c0373f7055f31042edcd5530 (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>
-rw-r--r--wayland/democompositor/processlauncher.cpp52
-rw-r--r--wayland/democompositor/processlauncher.h30
-rw-r--r--wayland/democompositor/qml/LaunchButton.qml5
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)
+ }
}