From bc7fbfb3a1ef32865f1dc3ddaddf752d5dac2d5c Mon Sep 17 00:00:00 2001 From: ComixHe Date: Wed, 13 Sep 2023 16:52:53 +0800 Subject: [PATCH] feat: add property Launcher, Orphaned refactor some method which are related with systemd unit Signed-off-by: ComixHe --- ...sktopspec.ApplicationManager1.Instance.xml | 16 ++++++ src/cgroupsidentifier.cpp | 2 +- src/dbus/applicationmanager1service.cpp | 55 +++++++++++-------- src/dbus/applicationmanager1service.h | 2 +- src/dbus/applicationservice.cpp | 13 +++-- src/dbus/applicationservice.h | 5 +- src/dbus/instanceservice.cpp | 16 ++---- src/dbus/instanceservice.h | 15 +++-- src/desktopentry.cpp | 20 ++++++- src/desktopentry.h | 13 ++++- src/global.h | 51 +++++++++++------ src/propertiesForwarder.cpp | 28 ++++++++-- src/systemdsignaldispatcher.cpp | 10 ++-- tests/ut_applicationmanager.cpp | 4 +- 14 files changed, 168 insertions(+), 82 deletions(-) diff --git a/api/dbus/org.desktopspec.ApplicationManager1.Instance.xml b/api/dbus/org.desktopspec.ApplicationManager1.Instance.xml index bfb7d66..d8eadff 100644 --- a/api/dbus/org.desktopspec.ApplicationManager1.Instance.xml +++ b/api/dbus/org.desktopspec.ApplicationManager1.Instance.xml @@ -25,5 +25,21 @@ if this instance is not managed by systemd." /> + + + + + + + + diff --git a/src/cgroupsidentifier.cpp b/src/cgroupsidentifier.cpp index ab434ff..61d710e 100644 --- a/src/cgroupsidentifier.cpp +++ b/src/cgroupsidentifier.cpp @@ -19,7 +19,7 @@ IdentifyRet CGroupsIdentifier::Identify(pid_t pid) auto UnitStr = parseCGroupsPath(AppCgroupFile); - auto [appId, InstanceId] = processUnitName(UnitStr); + auto [appId, launcher, InstanceId] = processUnitName(UnitStr); return {std::move(appId), std::move(InstanceId)}; } diff --git a/src/dbus/applicationmanager1service.cpp b/src/dbus/applicationmanager1service.cpp index 1d5b9cc..7eb1f09 100644 --- a/src/dbus/applicationmanager1service.cpp +++ b/src/dbus/applicationmanager1service.cpp @@ -103,9 +103,11 @@ void ApplicationManager1Service::addInstanceToApplication(const QString &unitNam return; } - auto pair = processUnitName(unitName); - auto appId = pair.first; - auto instanceId = pair.second; + auto info = processUnitName(unitName); + auto appId = std::move(info.applicationID); + auto launcher = std::move(info.Launcher); + auto instanceId = std::move(info.instanceID); + if (appId.isEmpty()) { return; } @@ -132,7 +134,7 @@ void ApplicationManager1Service::addInstanceToApplication(const QString &unitNam const auto &applicationPath = (*appIt)->applicationPath().path(); - if (!(*appIt)->addOneInstance(instanceId, applicationPath, systemdUnitPath.path())) [[likely]] { + if (!(*appIt)->addOneInstance(instanceId, applicationPath, systemdUnitPath.path(), launcher)) [[likely]] { qCritical() << "add Instance failed:" << applicationPath << unitName << systemdUnitPath.path(); } } @@ -143,9 +145,11 @@ void ApplicationManager1Service::removeInstanceFromApplication(const QString &un return; } - auto pair = processUnitName(unitName); - auto appId = pair.first; - auto instanceId = pair.second; + auto info = processUnitName(unitName); + auto appId = std::move(info.applicationID); + auto launcher = std::move(info.Launcher); + auto instanceId = std::move(info.instanceID); + if (appId.isEmpty()) { return; } @@ -163,12 +167,17 @@ void ApplicationManager1Service::removeInstanceFromApplication(const QString &un auto instanceIt = std::find_if(appIns.cbegin(), appIns.cend(), [&systemdUnitPath](const QSharedPointer &value) { - return value->systemdUnitPath() == systemdUnitPath; + return value->property("SystemdUnitPath") == systemdUnitPath; }); if (instanceIt != appIns.cend()) [[likely]] { (*appIt)->removeOneInstance(instanceIt.key()); + return; } + + orphanedInstances->removeIf([&systemdUnitPath](const QSharedPointer &ptr) { + return (ptr->property("SystemdUnitPath").value() == systemdUnitPath); + }); } void ApplicationManager1Service::scanApplications() noexcept @@ -357,28 +366,28 @@ QString ApplicationManager1Service::Identify(const QDBusUnixFileDescriptor &pidf } void ApplicationManager1Service::updateApplication(const QSharedPointer &destApp, - const DesktopFile &desktopFile) noexcept + DesktopFile desktopFile) noexcept { // TODO: add propertyChanged if (auto app = m_applicationList.find(destApp->applicationPath()); app == m_applicationList.cend()) { return; } - auto timeInfo = getFileTimeInfo(QFileInfo{desktopFile.sourceFileRef()}); + auto *newEntry = new (std::nothrow) DesktopEntry{}; + if (newEntry == nullptr) { + qCritical() << "new DesktopEntry failed."; + return; + } - if (destApp->desktopFileSource().modified(timeInfo.mtime)) { - auto *newEntry = new (std::nothrow) DesktopEntry{}; - if (newEntry == nullptr) { - qCritical() << "new DesktopEntry failed."; - return; - } + auto err = newEntry->parse(desktopFile); + if (err != DesktopErrorCode::NoError) { + qWarning() << "update desktop file failed:" << err << ", content wouldn't change."; + return; + } - auto err = newEntry->parse(destApp->desktopFileSource()); - if (err != DesktopErrorCode::NoError) { - qWarning() << "update desktop file failed:" << err << ", content wouldn't change."; - return; - } + if (destApp->m_entry != newEntry) { destApp->resetEntry(newEntry); + destApp->m_desktopSource = std::move(desktopFile); } } @@ -407,9 +416,9 @@ void ApplicationManager1Service::ReloadApplications() return false; } - if (destApp != m_applicationList.cend()) { + if (destApp != m_applicationList.cend() and apps.contains(destApp.key())) { apps.removeOne(destApp.key()); - updateApplication(destApp.value(), file); + updateApplication(destApp.value(), std::move(file)); return false; } diff --git a/src/dbus/applicationmanager1service.h b/src/dbus/applicationmanager1service.h index cfe8fcb..18cb369 100644 --- a/src/dbus/applicationmanager1service.h +++ b/src/dbus/applicationmanager1service.h @@ -39,7 +39,7 @@ public: void removeOneApplication(const QDBusObjectPath &application) noexcept; void removeAllApplication() noexcept; - void updateApplication(const QSharedPointer &destApp, const DesktopFile &desktopFile) noexcept; + void updateApplication(const QSharedPointer &destApp, DesktopFile desktopFile) noexcept; JobManager1Service &jobManager() noexcept { return *m_jobManager; } diff --git a/src/dbus/applicationservice.cpp b/src/dbus/applicationservice.cpp index c467cc0..bad298d 100644 --- a/src/dbus/applicationservice.cpp +++ b/src/dbus/applicationservice.cpp @@ -34,10 +34,8 @@ ApplicationService::ApplicationService(DesktopFile source, ApplicationService::~ApplicationService() { for (auto &instance : m_Instances.values()) { - instance->m_Application = QDBusObjectPath{"/"}; - auto *ptr = instance.get(); - instance.reset(nullptr); - ptr->setParent(qApp); // detach all instances to qApp + orphanedInstances->append(instance); + instance->m_orphaned = true; } } @@ -465,9 +463,12 @@ QList ApplicationService::instances() const noexcept return m_Instances.keys(); } -bool ApplicationService::addOneInstance(const QString &instanceId, const QString &application, const QString &systemdUnitPath) +bool ApplicationService::addOneInstance(const QString &instanceId, + const QString &application, + const QString &systemdUnitPath, + const QString &launcher) { - auto *service = new InstanceService{instanceId, application, systemdUnitPath}; + auto *service = new InstanceService{instanceId, application, systemdUnitPath, launcher}; auto *adaptor = new InstanceAdaptor(service); QString objectPath{m_applicationPath.path() + "/" + instanceId}; diff --git a/src/dbus/applicationservice.h b/src/dbus/applicationservice.h index f08fa5f..98239ac 100644 --- a/src/dbus/applicationservice.h +++ b/src/dbus/applicationservice.h @@ -86,7 +86,10 @@ public: [[nodiscard]] const QString &getLauncher() const noexcept { return m_launcher; } void setLauncher(const QString &launcher) noexcept { m_launcher = launcher; } - bool addOneInstance(const QString &instanceId, const QString &application, const QString &systemdUnitPath); + bool addOneInstance(const QString &instanceId, + const QString &application, + const QString &systemdUnitPath, + const QString &launcher); void recoverInstances(const QList &instanceList) noexcept; void removeOneInstance(const QDBusObjectPath &instance) noexcept; void removeAllInstance() noexcept; diff --git a/src/dbus/instanceservice.cpp b/src/dbus/instanceservice.cpp index 0032272..11d14ae 100644 --- a/src/dbus/instanceservice.cpp +++ b/src/dbus/instanceservice.cpp @@ -3,22 +3,14 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "dbus/instanceservice.h" +#include -InstanceService::InstanceService(QString instanceId, QString application, QString systemdUnitPath) - : m_instanceId(std::move(instanceId)) +InstanceService::InstanceService(QString instanceId, QString application, QString systemdUnitPath, QString launcher) + : m_Launcher(std::move(launcher)) + , m_instanceId(std::move(instanceId)) , m_Application(std::move(application)) , m_SystemdUnitPath(std::move(systemdUnitPath)) { } InstanceService::~InstanceService() = default; - -QDBusObjectPath InstanceService::application() const -{ - return m_Application; -} - -QDBusObjectPath InstanceService::systemdUnitPath() const -{ - return m_SystemdUnitPath; -} diff --git a/src/dbus/instanceservice.h b/src/dbus/instanceservice.h index bd9aa39..0f18ae0 100644 --- a/src/dbus/instanceservice.h +++ b/src/dbus/instanceservice.h @@ -18,20 +18,23 @@ public: InstanceService &operator=(const InstanceService &) = delete; InstanceService &operator=(InstanceService &&) = delete; - Q_PROPERTY(QDBusObjectPath Application READ application) - [[nodiscard]] QDBusObjectPath application() const; - - Q_PROPERTY(QDBusObjectPath SystemdUnitPath READ systemdUnitPath) - [[nodiscard]] QDBusObjectPath systemdUnitPath() const; + Q_PROPERTY(QDBusObjectPath Application MEMBER m_Application) + Q_PROPERTY(QDBusObjectPath SystemdUnitPath MEMBER m_SystemdUnitPath) + Q_PROPERTY(QString Launcher MEMBER m_Launcher) + Q_PROPERTY(bool Orphaned MEMBER m_orphaned) [[nodiscard]] const QString &instanceId() const noexcept { return m_instanceId; } private: friend class ApplicationService; - InstanceService(QString instanceId, QString application, QString systemdUnitPath); + InstanceService(QString instanceId, QString application, QString systemdUnitPath, QString launcher); + bool m_orphaned{false}; + QString m_Launcher; QString m_instanceId; QDBusObjectPath m_Application; QDBusObjectPath m_SystemdUnitPath; }; +Q_GLOBAL_STATIC(QList>, orphanedInstances) + #endif diff --git a/src/desktopentry.cpp b/src/desktopentry.cpp index 47b4028..b79405f 100644 --- a/src/desktopentry.cpp +++ b/src/desktopentry.cpp @@ -369,7 +369,7 @@ bool DesktopFile::modified(qint64 time) const noexcept return time != m_mtime; } -DesktopErrorCode DesktopEntry::parse(DesktopFile &file) noexcept +DesktopErrorCode DesktopEntry::parse(const DesktopFile &file) noexcept { DesktopFileGuard guard{file}; @@ -538,6 +538,24 @@ float DesktopEntry::Value::toNumeric(bool &ok) const noexcept return v.toFloat(&ok); } +bool operator==(const DesktopEntry &lhs, const DesktopEntry &rhs) +{ + if (lhs.m_parsed != rhs.m_parsed) { + return false; + } + + if (lhs.m_entryMap != rhs.m_entryMap) { + return false; + } + + return true; +} + +bool operator!=(const DesktopEntry &lhs, const DesktopEntry &rhs) +{ + return !(lhs == rhs); +} + QDebug operator<<(QDebug debug, const DesktopEntry::Value &v) { QDebugStateSaver saver{debug}; diff --git a/src/desktopentry.h b/src/desktopentry.h index e3827e2..be6d16c 100644 --- a/src/desktopentry.h +++ b/src/desktopentry.h @@ -80,7 +80,7 @@ struct DesktopFileGuard DesktopFileGuard &operator=(const DesktopFileGuard &) = delete; DesktopFileGuard &operator=(DesktopFileGuard &&) = delete; - explicit DesktopFileGuard(DesktopFile &file) + explicit DesktopFileGuard(const DesktopFile &file) : fileRef(file) { } @@ -107,7 +107,7 @@ struct DesktopFileGuard } private: - DesktopFile &fileRef; + const DesktopFile &fileRef; }; class DesktopEntry @@ -135,11 +135,14 @@ public: DesktopEntry &operator=(DesktopEntry &&) = default; ~DesktopEntry() = default; - [[nodiscard]] DesktopErrorCode parse(DesktopFile &file) noexcept; + [[nodiscard]] DesktopErrorCode parse(const DesktopFile &file) noexcept; [[nodiscard]] DesktopErrorCode parse(QTextStream &stream) noexcept; [[nodiscard]] std::optional> group(const QString &key) const noexcept; [[nodiscard]] std::optional value(const QString &key, const QString &valueKey) const noexcept; + friend bool operator==(const DesktopEntry &lhs, const DesktopEntry &rhs); + friend bool operator!=(const DesktopEntry &lhs, const DesktopEntry &rhs); + private: [[nodiscard]] bool checkMainEntryValidation() const noexcept; QMap> m_entryMap; @@ -150,4 +153,8 @@ QDebug operator<<(QDebug debug, const DesktopEntry::Value &v); QDebug operator<<(QDebug debug, const DesktopErrorCode &v); +bool operator==(const DesktopEntry &lhs, const DesktopEntry &rhs); + +bool operator!=(const DesktopEntry &lhs, const DesktopEntry &rhs); + #endif diff --git a/src/global.h b/src/global.h index 1f20817..7514dfa 100644 --- a/src/global.h +++ b/src/global.h @@ -233,11 +233,13 @@ inline QString getDBusInterface(const QMetaType &meta) if (name == "APPObjectManagerAdaptor" or name == "AMObjectManagerAdaptor") { return ObjectManagerInterface; } - // const auto *infoObject = meta.metaObject(); - // if (auto infoIndex = infoObject->indexOfClassInfo("D-Bus Interface"); infoIndex != -1) { - // return infoObject->classInfo(infoIndex).value(); - // } - qWarning() << "couldn't found interface:" << name; + + if (name == "ApplicationManager1Service") + // const auto *infoObject = meta.metaObject(); + // if (auto infoIndex = infoObject->indexOfClassInfo("D-Bus Interface"); infoIndex != -1) { + // return infoObject->classInfo(infoIndex).value(); + // } + qWarning() << "couldn't found interface:" << name; return ""; } @@ -425,31 +427,48 @@ inline bool isApplication(const QDBusObjectPath &path) return path.path().split('/').last().startsWith("app"); } -inline QPair processUnitName(const QString &unitName) +struct unitInfo +{ + QString applicationID; + QString Launcher; + QString instanceID; +}; + +inline unitInfo processUnitName(const QString &unitName) { QString instanceId; + QString launcher; QString applicationId; - if (unitName.endsWith(".service")) { - auto lastDotIndex = unitName.lastIndexOf('.'); - auto app = unitName.sliced(0, lastDotIndex); // remove suffix + decltype(auto) appPrefix = u8"app-"; + auto unit = unitName.sliced(sizeof(appPrefix) - 1); + + if (unit.endsWith(".service")) { + auto lastDotIndex = unit.lastIndexOf('.'); + auto app = unit.sliced(0, lastDotIndex); // remove suffix if (app.contains('@')) { auto atIndex = app.indexOf('@'); instanceId = app.sliced(atIndex + 1); app.remove(atIndex, instanceId.length() + 1); } - - applicationId = app.split('-').last(); // drop launcher if it exists. - } else if (unitName.endsWith(".scope")) { - auto lastDotIndex = unitName.lastIndexOf('.'); - auto app = unitName.sliced(0, lastDotIndex); + auto rest = app.split('-', Qt::SkipEmptyParts); + if (rest.size() == 2) { + launcher = rest.takeFirst(); + } + applicationId = rest.takeFirst(); + } else if (unit.endsWith(".scope")) { + auto lastDotIndex = unit.lastIndexOf('.'); + auto app = unit.sliced(0, lastDotIndex); auto components = app.split('-'); instanceId = components.takeLast(); applicationId = components.takeLast(); + if (!components.isEmpty()) { + launcher = components.takeLast(); + } } else { - qDebug() << "it's not service or scope:" << unitName << "ignore"; + qDebug() << "it's not service or scope:" << unit << "ignore"; return {}; } @@ -457,7 +476,7 @@ inline QPair processUnitName(const QString &unitName) instanceId = QUuid::createUuid().toString(QUuid::Id128); } - return qMakePair(unescapeApplicationId(applicationId), std::move(instanceId)); + return {unescapeApplicationId(applicationId), std::move(launcher), std::move(instanceId)}; } template diff --git a/src/propertiesForwarder.cpp b/src/propertiesForwarder.cpp index b22ac94..54fdff9 100644 --- a/src/propertiesForwarder.cpp +++ b/src/propertiesForwarder.cpp @@ -42,12 +42,32 @@ void PropertiesForwarder::PropertyChanged() return; } - auto sig = mo->property(sigIndex + 1); - const auto *propName = sig.name(); - auto value = sig.read(sender); + auto sig = mo->method(sigIndex); + auto signature = sig.methodSignature(); + + QByteArray propName; + for (auto i = mo->propertyOffset(); i < mo->propertyCount(); ++i) { + auto prop = mo->property(i); + if (!prop.hasNotifySignal()) { + continue; + } + + if (prop.notifySignal().methodSignature() == signature) { + propName = prop.name(); + } + } + + if (propName.isEmpty()) { + qDebug() << "can't find corresponding property:" << signature; + return; + } + + auto propIndex = mo->indexOfProperty(propName.constData()); + auto prop = mo->property(propIndex); + auto value = prop.read(sender); - auto childs = sender->children(); auto msg = QDBusMessage::createSignal(m_path, "org.freedesktop.DBus.Properties", "PropertiesChanged"); + msg << QString{ApplicationInterface}; msg << QVariantMap{{QString{propName}, value}}; msg << QStringList{}; diff --git a/src/systemdsignaldispatcher.cpp b/src/systemdsignaldispatcher.cpp index 4c806cc..4308ef3 100644 --- a/src/systemdsignaldispatcher.cpp +++ b/src/systemdsignaldispatcher.cpp @@ -33,20 +33,18 @@ bool SystemdSignalDispatcher::connectToSignals() noexcept void SystemdSignalDispatcher::onUnitNew(QString unitName, QDBusObjectPath systemdUnitPath) { - decltype(auto) appPrefix = u8"app-"; - if (!unitName.startsWith(appPrefix)) { + if (!unitName.startsWith("app-")) { return; } - emit SystemdUnitNew(unitName.sliced(sizeof(appPrefix) - 1), systemdUnitPath); + emit SystemdUnitNew(unitName, systemdUnitPath); } void SystemdSignalDispatcher::onUnitRemoved(QString unitName, QDBusObjectPath systemdUnitPath) { - decltype(auto) appPrefix = u8"app-"; - if (!unitName.startsWith(appPrefix)) { + if (!unitName.startsWith("app-")) { return; } - emit SystemdUnitRemoved(unitName.sliced(sizeof(appPrefix) - 1), systemdUnitPath); + emit SystemdUnitRemoved(unitName, systemdUnitPath); } diff --git a/tests/ut_applicationmanager.cpp b/tests/ut_applicationmanager.cpp index 301c5e2..a68fbbb 100644 --- a/tests/ut_applicationmanager.cpp +++ b/tests/ut_applicationmanager.cpp @@ -38,8 +38,8 @@ public: auto ptr = std::make_unique(QString{"/usr/share/applications/test-Application.desktop"}); DesktopFile file{std::move(ptr), "test-Application", 0, 0}; QSharedPointer app = QSharedPointer::create(std::move(file), nullptr, tmp); - QSharedPointer instance = - QSharedPointer::create(InstancePath.path().split('/').last(), ApplicationPath.path(), QString{"/"}); + QSharedPointer instance = QSharedPointer::create( + InstancePath.path().split('/').last(), ApplicationPath.path(), QString{"/"}, QString{"DDE"}); app->m_Instances.insert(InstancePath, instance); m_am->m_applicationList.insert(ApplicationPath, app); }