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);
}