Paste P577

(An Untitled Masterwork)
ActivePublic

Authored by hchain on Apr 8 2020, 1:20 PM.
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index 665bfb72..bf5c2f3d 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -7,6 +7,15 @@ set(kiogui_SRCS
kprocessrunner.cpp
)
+set(SYSTEMD_DBUS_XMLS
+ systemd/org.freedesktop.systemd1.Manager.xml
+ systemd/org.freedesktop.systemd1.Unit.xml
+ systemd/org.freedesktop.DBus.Properties.xml)
+
+set_source_files_properties(${SYSTEMD_DBUS_XMLS} PROPERTIES INCLUDE systemd/dbustypes.h)
+
+qt5_add_dbus_interfaces(kiogui_SRCS ${SYSTEMD_DBUS_XMLS})
+
ecm_qt_declare_logging_category(kiogui_SRCS
HEADER kiogui_debug.h
IDENTIFIER KIO_GUI
diff --git a/src/gui/applicationlauncherjob.cpp b/src/gui/applicationlauncherjob.cpp
index f46e6eaa..87a74137 100644
--- a/src/gui/applicationlauncherjob.cpp
+++ b/src/gui/applicationlauncherjob.cpp
@@ -41,7 +41,7 @@ public:
QString m_suggestedFileName;
QByteArray m_startupId;
QVector<qint64> m_pids;
- QVector<KProcessRunner *> m_processRunners;
+ QVector<QPointer<KProcessRunner>> m_processRunners;
int m_numProcessesPending = 0;
};
@@ -123,9 +123,11 @@ bool KIO::ApplicationLauncherJob::waitForStarted()
{
const bool ret = std::all_of(d->m_processRunners.cbegin(),
d->m_processRunners.cend(),
- [](KProcessRunner *r) { return r->waitForStarted(); });
+ [](KProcessRunner *r) { return r ? r->waitForStarted() : true; });
for (KProcessRunner *r : qAsConst(d->m_processRunners)) {
- qApp->sendPostedEvents(r); // so slotStarted gets called
+ if (r) {
+ qApp->sendPostedEvents(r); // so slotStarted gets called
+ }
}
return ret;
}
diff --git a/src/gui/kprocessrunner.cpp b/src/gui/kprocessrunner.cpp
index 0021b5e1..8e844abd 100644
--- a/src/gui/kprocessrunner.cpp
+++ b/src/gui/kprocessrunner.cpp
@@ -25,6 +25,9 @@
#include "desktopexecparser.h"
#include "krecentdocument.h"
+#include "managerinterface.h"
+#include "propertiesinterface.h"
+#include "unitinterface.h"
#include <KDesktopFile>
#include <KLocalizedString>
#include <KWindowSystem>
@@ -40,16 +43,44 @@
#include <QStandardPaths>
#include <QUuid>
-#include <mutex>
+#ifdef Q_OS_LINUX
+#include <signal.h>
+#endif
+
+
+using namespace org::freedesktop;
static int s_instanceCount = 0; // for the unittest
+static const auto systemdService = QStringLiteral("org.freedesktop.systemd1");
+
+static bool runAsService = false;
+
+KProcessRunner::KProcessRunner(const QString &executable)
+ : m_process {new KProcess}
+ , m_executable(executable)
+{
+ ++s_instanceCount;
+#ifdef Q_OS_LINUX
+ static std::once_flag dbusRegistered;
+ std::call_once(dbusRegistered, []() {
+ if (qEnvironmentVariableIsSet("KDE_APPLICATIONS_AS_SCOPE") && (QDBusConnection::sessionBus().interface()->isServiceRegistered(systemdService))) {
+ runAsService = true;
+ qDBusRegisterMetaType<QVariantMultiItem>();
+ qDBusRegisterMetaType<QVariantMultiMap>();
+ qDBusRegisterMetaType<TransientAux>();
+ qDBusRegisterMetaType<TransientAuxList>();
+ qDBusRegisterMetaType<ExecCommand>();
+ qDBusRegisterMetaType<ExecCommandList>();
+ }
+ });
+#endif
+}
+
KProcessRunner::KProcessRunner(const KService::Ptr &service, const QList<QUrl> &urls,
KIO::ApplicationLauncherJob::RunFlags flags, const QString &suggestedFileName, const QByteArray &asn)
- : m_process{new KProcess},
- m_executable(KIO::DesktopExecParser::executablePath(service->exec()))
+ : KProcessRunner(KIO::DesktopExecParser::executablePath(service->exec()))
{
- ++s_instanceCount;
KIO::DesktopExecParser execParser(*service, urls);
const QString realExecutable = execParser.resultingArguments().at(0);
@@ -109,10 +140,8 @@ KProcessRunner::KProcessRunner(const KService::Ptr &service, const QList<QUrl> &
}
KProcessRunner::KProcessRunner(const QString &cmd, const QString &desktopName, const QString &execName, const QString &iconName, const QByteArray &asn, const QString &workingDirectory)
- : m_process{new KProcess},
- m_executable(execName)
+ : KProcessRunner::KProcessRunner(execName)
{
- ++s_instanceCount;
m_process->setShellCommand(cmd);
if (!workingDirectory.isEmpty()) {
m_process->setWorkingDirectory(workingDirectory);
@@ -183,17 +212,25 @@ void KProcessRunner::init(const KService::Ptr &service, const QString &userVisib
Q_UNUSED(userVisibleName);
Q_UNUSED(iconName);
#endif
+#ifdef Q_OS_LINUX
if (service) {
- m_scopeId = service->desktopEntryName();
+ m_serviceId = service->desktopEntryName();
}
- if (m_scopeId.isEmpty()) {
- m_scopeId = m_executable;
+ if (m_serviceId.isEmpty()) {
+ m_serviceId = m_executable;
}
+#endif
startProcess();
}
void KProcessRunner::startProcess()
{
+#ifdef Q_OS_LINUX
+ if (runAsService) {
+ // As specified in "XDG standardization for applications" in https://systemd.io/DESKTOP_ENVIRONMENTS/
+ return startAsService();
+ }
+#endif
connect(m_process.get(), QOverload<int,QProcess::ExitStatus>::of(&QProcess::finished),
this, &KProcessRunner::slotProcessExited);
connect(m_process.get(), &QProcess::started,
@@ -204,9 +241,26 @@ void KProcessRunner::startProcess()
m_process->start();
}
-bool KProcessRunner::waitForStarted()
+bool KProcessRunner::waitForStarted(int timeout)
{
- return m_process->waitForStarted();
+#ifdef Q_OS_LINUX
+ if (runAsService) {
+ if (m_pid || m_exited) {
+ return true;
+ }
+ QEventLoop loop;
+ bool success = false;
+ loop.connect(this, &KProcessRunner::processStarted, [&loop, &success] () {
+ loop.quit();
+ success = true;
+ });
+ QTimer::singleShot(timeout, &loop, &QEventLoop::quit);
+ QObject::connect(this, &KProcessRunner::error, &loop, &QEventLoop::quit);
+ loop.exec();
+ return success;
+ }
+#endif
+ return m_process->waitForStarted(timeout);
}
void KProcessRunner::slotProcessError(QProcess::ProcessError errorCode)
@@ -218,20 +272,26 @@ void KProcessRunner::slotProcessError(QProcess::ProcessError errorCode)
Q_EMIT error(m_process->errorString());
}
-void KProcessRunner::slotProcessStarted()
+void KProcessRunner::setPid(qint64 pid)
{
- m_pid = m_process->processId();
- registerCGroup();
-
+ if (!m_pid && pid) {
+ qCDebug(KIO_GUI) << "Setting PID" << pid << "for:" << m_executable;
+ m_pid = pid;
#if HAVE_X11
- if (!m_startupId.isNull() && m_pid) {
- KStartupInfoData data;
- data.addPid(m_pid);
- KStartupInfo::sendChange(m_startupId, data);
- KStartupInfo::resetStartupEnv();
- }
+ if (!m_startupId.isNull()) {
+ KStartupInfoData data;
+ data.addPid(static_cast<int>(m_pid));
+ KStartupInfo::sendChange(m_startupId, data);
+ KStartupInfo::resetStartupEnv();
+ }
#endif
- emit processStarted();
+ Q_EMIT processStarted();
+ }
+}
+
+void KProcessRunner::slotProcessStarted()
+{
+ setPid(m_process->processId());
}
KProcessRunner::~KProcessRunner()
@@ -255,7 +315,7 @@ void KProcessRunner::terminateStartupNotification()
#if HAVE_X11
if (!m_startupId.isNull()) {
KStartupInfoData data;
- data.addPid(m_pid); // announce this pid for the startup notification has finished
+ data.addPid(static_cast<int>(m_pid)); // announce this pid for the startup notification has finished
data.setHostname();
KStartupInfo::sendFinish(m_startupId, data);
}
@@ -274,68 +334,154 @@ void KProcessRunner::emitDelayedError(const QString &errorMsg)
void KProcessRunner::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus)
{
- qCDebug(KIO_GUI) << m_executable << "exitCode=" << exitCode << "exitStatus=" << exitStatus;
+ qCDebug(KIO_GUI) << m_executable << "pid=" << m_pid << "exitCode=" << exitCode << "exitStatus=" << exitStatus;
terminateStartupNotification();
deleteLater();
}
-void KProcessRunner::registerCGroup()
-{
- // As specified in "XDG standardization for applications" in https://systemd.io/DESKTOP_ENVIRONMENTS/
#ifdef Q_OS_LINUX
- if (!qEnvironmentVariableIsSet("KDE_APPLICATIONS_AS_SCOPE")) {
- return;
- }
- if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.freedesktop.systemd1"))) {
- return;
+// Only alphanum, ':' and '_' allowed in systemd unit names
+QString escapeUnitName(const QString &input)
+{
+ QString res;
+ for (const auto &c : input.toUtf8()) {
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= 0 && c <= 9) || c == ':' || c == '_' ||
+ c == '.') {
+ res += QLatin1Char(c);
+ } else {
+ res += QStringLiteral("\\x%1").arg(c, 2, 16, QLatin1Char('0'));
+ }
}
+ return res;
+}
- typedef QPair<QString, QDBusVariant> NamedVariant;
- typedef QList<NamedVariant> NamedVariantList;
-
- static std::once_flag dbusTypesRegistered;
- std::call_once(dbusTypesRegistered, []() {
- qDBusRegisterMetaType<NamedVariant>();
- qDBusRegisterMetaType<NamedVariantList>();
- qDBusRegisterMetaType<QPair<QString, NamedVariantList>>();
- qDBusRegisterMetaType<QList<QPair<QString, NamedVariantList>>>();
- });
-
- QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.systemd1"),
- QStringLiteral("/org/freedesktop/systemd1"),
- QStringLiteral("org.freedesktop.systemd1.Manager"),
- QStringLiteral("StartTransientUnit"));
-
- // "-" is a special character in systemd representing a heirachical level. It should be escaped.
- const QString escapedScopeId = m_scopeId.replace(QLatin1Char('-'), QStringLiteral("\\x2d"));
-
- const QString name = QStringLiteral("apps-%1-%2.scope").arg(escapedScopeId, QUuid::createUuid().toString(QUuid::Id128));
+// Probably belongs in KProcess ?
+void KProcessRunner::startAsService()
+{
+ m_serviceName = QStringLiteral("apps-%1-%2.service").arg(escapeUnitName(m_serviceId), QUuid::createUuid().toString(QUuid::Id128));
+
+ // Watch for new services
+ m_manager = new systemd1::Manager(systemdService, QStringLiteral("/org/freedesktop/systemd1"), QDBusConnection::sessionBus(), this);
+ m_manager->Subscribe();
+ connect(m_manager, &systemd1::Manager::UnitNew, this, &KProcessRunner::handleUnitNew);
+
+ // Watch for service creation job error
+ connect(m_manager,
+ &systemd1::Manager::JobRemoved,
+ this,
+ [this](uint jobId, const QDBusObjectPath &jobPath, const QString &unitName, const QString &result) {
+ Q_UNUSED(jobId)
+ if (jobPath.path() == m_jobPath && unitName == m_serviceName && result != QStringLiteral("done")) {
+ qCWarning(KIO_GUI) << "Failed to launch process as service:" << m_serviceName << ", result "
+ << result;
+ // result=failed is not a fatal error, service is actually created in this case
+ if (result != QStringLiteral("failed")) {
+ systemdError(result);
+ }
+ }
+ });
+
+ // Ask systemd for a new transient service
// mode defines what to do in the case of a name conflict, in this case, just do nothing
const QString mode = QStringLiteral("fail");
+ const QVariantMultiMap properties = {
+ {QStringLiteral("Type"), QStringLiteral("oneshot")},
+ {QStringLiteral("Environment"), m_process->environment()},
+ {QStringLiteral("AddRef"), true}, // https://www.freedesktop.org/software/systemd/man/sd_bus_track_new.html
+ {QStringLiteral("WorkingDirectory"), m_process->workingDirectory()},
+ {QStringLiteral("ExecStart"), QVariant::fromValue(ExecCommandList {{m_process->program().first(), m_process->program(), false}})}};
+
+ const auto startReply = m_manager->StartTransientUnit(m_serviceName, mode, properties, TransientAuxList {});
+ connect(new QDBusPendingCallWatcher(startReply, this),
+ &QDBusPendingCallWatcher::finished,
+ [this](QDBusPendingCallWatcher *watcher) {
+ QDBusPendingReply<QDBusObjectPath> reply = *watcher;
+ if (reply.isError()) {
+ qCWarning(KIO_GUI) << "Failed to launch process as service:" << m_serviceName
+ << reply.error().name() << reply.error().message();
+ systemdError(reply.error().name());
+ } else {
+ qCDebug(KIO_GUI) << "Successfully asked systemd to launch process as service:" << m_serviceName;
+ m_jobPath = reply.argumentAt<0>().path();
+ }
+ watcher->deleteLater();
+ });
+}
- const QList<uint> pidList = {static_cast<quint32>(m_process->pid())};
-
- NamedVariantList properties = {NamedVariant({QStringLiteral("PIDs"), QDBusVariant(QVariant::fromValue(pidList))})};
-
- QList<QPair<QString, NamedVariantList>> aux;
-
- message.setArguments({name, mode, QVariant::fromValue(properties), QVariant::fromValue(aux)});
- QDBusPendingCall reply = QDBusConnection::sessionBus().asyncCall(message);
-
- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
-
- QObject::connect(watcher, &QDBusPendingCallWatcher::finished, qApp, [=]() {
- watcher->deleteLater();
- if (reply.isError()) {
- qCWarning(KIO_GUI) << "Failed to register new cgroup:" << name;
- } else {
- qCDebug(KIO_GUI) << "Successfully registered new cgroup:" << name;
+void KProcessRunner::handleProperties(QDBusPendingCallWatcher *watcher)
+{
+ m_propertyGetPending = false;
+ const QDBusPendingReply<QVariantMap> reply = *watcher;
+ if (reply.isError()) {
+ myWarning(KIO_GUI) << "Failed to get properties for service:" << m_serviceName << reply.error().name()
+ << reply.error().message();
+ systemdError(reply.error().name());
+ } else {
+ myDebug(KIO_GUI) << "Successfully retrieved properties for service:" << m_serviceName;
+ const auto properties = reply.argumentAt<0>();
+ setPid(properties[QStringLiteral("ExecMainPID")].value<quint32>());
+ const auto activeState = properties[QStringLiteral("ActiveState")].toString();
+ if (m_pid && !m_exited && (activeState == QStringLiteral("inactive") || activeState == QStringLiteral("failed"))) {
+ m_exited = true;
+// const auto result = properties[QStringLiteral("Result")].toString();
+
+ // ExecMainCode/Status correspond to si_code/si_status in the siginfo_t structure
+ // ExecMainCode is the signal code: CLD_EXITED (1) for normal exit
+ // ExecMainStatus is the process exit code in case of normal exit, otherwise it is the signal number
+ const auto signalCode = properties[QStringLiteral("ExecMainCode")].value<qint32>();
+ const auto exitCodeOrSignalNumber = properties[QStringLiteral("ExecMainStatus")].value<qint32>();
+ const auto exitStatus = signalCode == CLD_EXITED ? QProcess::ExitStatus::NormalExit : QProcess::ExitStatus::CrashExit;
+
+ qCDebug(KIO_GUI) << m_serviceId << "pid=" << m_pid << "exitCode=" << exitCodeOrSignalNumber << "exitStatus=" << exitStatus;
+ terminateStartupNotification();
+
+ systemd1::Unit unitInterface(systemdService, m_servicePath, QDBusConnection::sessionBus(), this);
+ connect(new QDBusPendingCallWatcher(unitInterface.Unref(), this),
+ &QDBusPendingCallWatcher::finished,
+ [this](QDBusPendingCallWatcher *watcher) {
+ QDBusPendingReply<> reply = *watcher;
+ if (reply.isError()) {
+ qCWarning(KIO_GUI) << "Failed to unref service:" << m_serviceName << reply.error().name()
+ << reply.error().message();
+ systemdError(reply.error().name());
+ } else {
+ qCDebug(KIO_GUI) << "Successfully unref'd service:" << m_serviceName;
+ }
+ watcher->deleteLater();
+ deleteLater();
+ });
}
- });
+ }
+ watcher->deleteLater();
+}
-#endif
+void KProcessRunner::handleUnitNew(const QString &newName, const QDBusObjectPath &newPath) {
+ if (newName == m_serviceName) {
+ qCDebug(KIO_GUI) << "Successfully launched process as service:" << m_serviceName;
+
+ // Get PID (and possibly exit code) from systemd service properties
+ m_servicePath = newPath.path();
+ m_serviceProperties = new DBus::Properties(systemdService, m_servicePath, QDBusConnection::sessionBus(), this);
+ auto propReply = m_serviceProperties->GetAll(QString());
+ connect(new QDBusPendingCallWatcher(propReply, this), &QDBusPendingCallWatcher::finished, this, &KProcessRunner::handleProperties);
+
+ // Watch for status change
+ connect(m_serviceProperties, &DBus::Properties::PropertiesChanged, [this] (const QString &interface, const QVariantMap &changed, const QStringList &invalidated) {
+ qCDebug(KIO_GUI) << "Got propertyChanged signal:" << m_serviceName;
+ if (!m_exited && !m_propertyGetPending) {
+ // Get all properties because changed signal only tells us those that changed, one interface at a time
+ m_propertyGetPending = true;
+ connect(new QDBusPendingCallWatcher(m_serviceProperties->GetAll(QString()), this), &QDBusPendingCallWatcher::finished, this, &KProcessRunner::handleProperties);
+ }
+ });
+ }
}
+void KProcessRunner::systemdError(const QString &message) {
+ Q_EMIT error(message);
+ deleteLater();
+}
+#endif
// This code is also used in klauncher (and KRun).
bool KIOGuiPrivate::checkStartupNotify(const KService *service, bool *silent_arg, QByteArray *wmclass_arg)
diff --git a/src/gui/kprocessrunner_p.h b/src/gui/kprocessrunner_p.h
index 0a309603..da98e361 100644
--- a/src/gui/kprocessrunner_p.h
+++ b/src/gui/kprocessrunner_p.h
@@ -30,6 +30,13 @@
#include <memory>
#include <KStartupInfo>
+#ifdef Q_OS_LINUX
+class OrgFreedesktopSystemd1ManagerInterface;
+class OrgFreedesktopDBusPropertiesInterface;
+class QDBusObjectPath;
+class QDBusPendingCallWatcher;
+#endif
+
namespace KIOGuiPrivate {
/**
* @internal DO NOT USE
@@ -80,7 +87,7 @@ public:
*/
qint64 pid() const;
- bool waitForStarted();
+ bool waitForStarted(int timeout = 30000);
virtual ~KProcessRunner();
@@ -104,17 +111,33 @@ private Q_SLOTS:
void slotProcessStarted();
private:
+ KProcessRunner(const QString &executable);
void init(const KService::Ptr &service, const QString &userVisibleName,
const QString &iconName, const QByteArray &asn);
+ void setPid(qint64 pid);
void startProcess();
- void registerCGroup();
void terminateStartupNotification();
void emitDelayedError(const QString &errorMsg);
+#ifdef Q_OS_LINUX
+ void startAsService();
+ void handleProperties(QDBusPendingCallWatcher *watcher);
+ void handleUnitNew(const QString &newName, const QDBusObjectPath &newPath);
+ void systemdError(const QString &error);
+
+ QString m_serviceId;
+ QString m_serviceName;
+ QString m_servicePath;
+ QString m_jobPath;
+ bool m_exited = false;
+ bool m_propertyGetPending = false;
+ OrgFreedesktopSystemd1ManagerInterface *m_manager;
+ OrgFreedesktopDBusPropertiesInterface *m_serviceProperties;
+#endif
+
std::unique_ptr<KProcess> m_process;
QString m_executable; // can be a full path
KStartupInfoId m_startupId;
- QString m_scopeId;
qint64 m_pid = 0;
Q_DISABLE_COPY(KProcessRunner)
diff --git a/src/gui/systemd/dbustypes.h b/src/gui/systemd/dbustypes.h
new file mode 100644
index 00000000..bba74f18
--- /dev/null
+++ b/src/gui/systemd/dbustypes.h
@@ -0,0 +1,78 @@
+#ifndef DBUSTYPES_H
+#define DBUSTYPES_H
+
+#include <QDBusArgument>
+
+using QVariantMultiItem = struct QVariantMultiItem {
+ QString key;
+ QVariant value;
+};
+Q_DECLARE_METATYPE(QVariantMultiItem)
+using QVariantMultiMap = QList<QVariantMultiItem>;
+Q_DECLARE_METATYPE(QVariantMultiMap)
+
+inline QDBusArgument &operator<<(QDBusArgument &argument, const QVariantMultiItem &item)
+{
+ argument.beginStructure();
+ argument << item.key << QDBusVariant(item.value);
+ argument.endStructure();
+ return argument;
+}
+
+inline const QDBusArgument &operator>>(const QDBusArgument &argument, QVariantMultiItem &item)
+{
+ argument.beginStructure();
+ argument >> item.key >> item.value;
+ argument.endStructure();
+ return argument;
+}
+
+using ExecCommand = struct ExecCommand {
+ QString path;
+ QStringList argv;
+ bool ignoreFailure;
+};
+Q_DECLARE_METATYPE(ExecCommand)
+using ExecCommandList = QList<ExecCommand>;
+Q_DECLARE_METATYPE(ExecCommandList)
+
+inline QDBusArgument &operator<<(QDBusArgument &argument, const ExecCommand &execCommand)
+{
+ argument.beginStructure();
+ argument << execCommand.path << execCommand.argv << execCommand.ignoreFailure;
+ argument.endStructure();
+ return argument;
+}
+
+inline const QDBusArgument &operator>>(const QDBusArgument &argument, ExecCommand &execCommand)
+{
+ argument.beginStructure();
+ argument >> execCommand.path >> execCommand.argv >> execCommand.ignoreFailure;
+ return argument;
+}
+
+using TransientAux = struct TransientAux {
+ QString name;
+ QVariantMultiMap properties;
+};
+Q_DECLARE_METATYPE(TransientAux)
+using TransientAuxList = QList<TransientAux>;
+Q_DECLARE_METATYPE(TransientAuxList)
+
+inline QDBusArgument &operator<<(QDBusArgument &argument, const TransientAux &aux)
+{
+ argument.beginStructure();
+ argument << aux.name << aux.properties;
+ argument.endStructure();
+ return argument;
+}
+
+inline const QDBusArgument &operator>>(const QDBusArgument &argument, TransientAux &aux)
+{
+ argument.beginStructure();
+ argument >> aux.name >> aux.properties;
+ argument.endStructure();
+ return argument;
+}
+
+#endif // DBUSTYPES_H
diff --git a/src/gui/systemd/org.freedesktop.DBus.Properties.xml b/src/gui/systemd/org.freedesktop.DBus.Properties.xml
new file mode 100644
index 00000000..9f55c138
--- /dev/null
+++ b/src/gui/systemd/org.freedesktop.DBus.Properties.xml
@@ -0,0 +1,22 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.freedesktop.DBus.Properties">
+ <method name="Get">
+ <arg name="interface" direction="in" type="s"/>
+ <arg name="property" direction="in" type="s"/>
+ <arg name="value" direction="out" type="v"/>
+ </method>
+ <method name="GetAll">
+ <arg name="interface" direction="in" type="s"/>
+ <arg name="properties" direction="out" type="a{sv}"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
+ </method>
+ <signal name="PropertiesChanged">
+ <arg type="s" name="interface"/>
+ <arg type="a{sv}" name="changed_properties"/>
+ <arg type="as" name="invalidated_properties"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap" />
+ </signal>
+ </interface>
+</node>
diff --git a/src/gui/systemd/org.freedesktop.systemd1.Manager.xml b/src/gui/systemd/org.freedesktop.systemd1.Manager.xml
new file mode 100644
index 00000000..3afcd051
--- /dev/null
+++ b/src/gui/systemd/org.freedesktop.systemd1.Manager.xml
@@ -0,0 +1,33 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.freedesktop.systemd1.Manager">
+ <method name="StartTransientUnit">
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="QVariantMultiMap"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In3" value="TransientAuxList"/>
+ <arg name="name" type="s" direction="in"/>
+ <arg name="mode" type="s" direction="in"/>
+ <arg name="properties" type="a(sv)" direction="in">
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="QVariantMultiMap"/>
+ </arg>
+ <arg name="aux" type="a(sa(sv))" direction="in">
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In3" value="TransientAuxList"/>
+ </arg>
+ <arg type="o" direction="out"/>
+ </method>
+ <method name="Subscribe">
+ </method>
+ <method name="Unsubscribe">
+ </method>
+ <signal name="UnitNew">
+ <arg name="name" type="s"/>
+ <arg name="path" type="o"/>
+ </signal>
+ <signal name="JobRemoved">
+ <arg name="id" type="u"/>
+ <arg name="job" type="o"/>
+ <arg name="unit" type="s"/>
+ <arg name="result" type="s"/>
+ </signal>
+ </interface>
+</node>
diff --git a/src/gui/systemd/org.freedesktop.systemd1.Unit.xml b/src/gui/systemd/org.freedesktop.systemd1.Unit.xml
new file mode 100644
index 00000000..5bd9e18b
--- /dev/null
+++ b/src/gui/systemd/org.freedesktop.systemd1.Unit.xml
@@ -0,0 +1,8 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.freedesktop.systemd1.Unit">
+ <method name="Unref">
+ </method>
+ </interface>
+</node>
hchain created this paste.Apr 8 2020, 1:20 PM
hchain created this object in space S1 KDE Community.
hchain edited the content of this paste. (Show Details)Apr 10 2020, 10:12 PM
hchain edited the content of this paste. (Show Details)
hchain edited the content of this paste. (Show Details)Apr 17 2020, 1:00 PM
hchain edited the content of this paste. (Show Details)Apr 21 2020, 5:16 PM