diff --git a/api/dbus/org.desktopspec.ApplicationManager1.Instance.xml b/api/dbus/org.desktopspec.ApplicationManager1.Instance.xml index a502daa..bfb7d66 100644 --- a/api/dbus/org.desktopspec.ApplicationManager1.Instance.xml +++ b/api/dbus/org.desktopspec.ApplicationManager1.Instance.xml @@ -4,9 +4,12 @@ diff --git a/api/dbus/org.desktopspec.ApplicationManager1.xml b/api/dbus/org.desktopspec.ApplicationManager1.xml index 7b700f3..12f933e 100644 --- a/api/dbus/org.desktopspec.ApplicationManager1.xml +++ b/api/dbus/org.desktopspec.ApplicationManager1.xml @@ -30,6 +30,5 @@ 1. You should use pidfd_open(2) to get a pidfd." /> - diff --git a/api/dbus/org.desktopspec.ObjectManager1.xml b/api/dbus/org.desktopspec.ObjectManager1.xml new file mode 100644 index 0000000..c1fbe2a --- /dev/null +++ b/api/dbus/org.desktopspec.ObjectManager1.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/apps/dde-application-manager/src/main.cpp b/apps/dde-application-manager/src/main.cpp index d25aeba..16882bb 100644 --- a/apps/dde-application-manager/src/main.cpp +++ b/apps/dde-application-manager/src/main.cpp @@ -15,6 +15,7 @@ void registerComplexDbusType() qDBusRegisterMetaType>(); qDBusRegisterMetaType>>(); qDBusRegisterMetaType(); + qDBusRegisterMetaType(); } } // namespace diff --git a/src/dbus/CMakeLists.txt b/src/dbus/CMakeLists.txt index ae56a0b..afbfd82 100644 --- a/src/dbus/CMakeLists.txt +++ b/src/dbus/CMakeLists.txt @@ -11,7 +11,8 @@ qt_add_dbus_adaptor(dde_am_dbus_SOURCE ${PROJECT_SOURCE_DIR}/api/dbus/org.deskto qt_add_dbus_adaptor(dde_am_dbus_SOURCE ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.ApplicationManager1.Instance.xml dbus/instanceservice.h InstanceService) qt_add_dbus_adaptor(dde_am_dbus_SOURCE ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.JobManager1.xml dbus/jobmanager1service.h JobManager1Service) qt_add_dbus_adaptor(dde_am_dbus_SOURCE ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.JobManager1.Job.xml dbus/jobservice.h JobService) - +qt_add_dbus_adaptor(dde_am_dbus_SOURCE ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.ObjectManager1.xml dbus/applicationmanager1service.h ApplicationManager1Service AMobjectmanager1adaptor AMObjectManagerAdaptor) +qt_add_dbus_adaptor(dde_am_dbus_SOURCE ${PROJECT_SOURCE_DIR}/api/dbus/org.desktopspec.ObjectManager1.xml dbus/applicationservice.h ApplicationService APPobjectmanager1adaptor APPObjectManagerAdaptor) target_sources(dde_am_dbus PRIVATE ${dde_am_dbus_SOURCE} diff --git a/src/dbus/applicationmanager1service.cpp b/src/dbus/applicationmanager1service.cpp index 19ef5d3..ad06dee 100644 --- a/src/dbus/applicationmanager1service.cpp +++ b/src/dbus/applicationmanager1service.cpp @@ -1,8 +1,9 @@ // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later -#include "dbus/applicationmanager1service.h" + #include "dbus/applicationmanager1adaptor.h" +#include "dbus/AMobjectmanager1adaptor.h" #include "systemdsignaldispatcher.h" #include #include @@ -17,8 +18,14 @@ ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr())) { + if (tmp == nullptr) { + std::terminate(); + } + + if (!registerObjectToDBus( + this, DDEApplicationManager1ObjectPath, getDBusInterface(QMetaType::fromType()))) { std::terminate(); } @@ -98,6 +105,7 @@ QList ApplicationManager1Service::list() const void ApplicationManager1Service::removeOneApplication(const QDBusObjectPath &application) { if (auto it = m_applicationList.find(application); it != m_applicationList.cend()) { + emit InterfacesRemoved(application, getInterfacesListFromObject(it->data())); unregisterObjectFromDBus(application.path()); m_applicationList.remove(application); } @@ -207,3 +215,15 @@ void ApplicationManager1Service::UpdateApplicationInfo(const QStringList &appIdL addApplication(std::move(file).value()); } } + +ObjectMap ApplicationManager1Service::GetManagedObjects() const +{ + ObjectMap objs; + + for (const auto &[key, value] : m_applicationList.asKeyValueRange()) { + auto interfaces = getInterfacesListFromObject(value.data()); + objs.insert(key, interfaces); + } + + return objs; +} diff --git a/src/dbus/applicationmanager1service.h b/src/dbus/applicationmanager1service.h index d798d85..b9add4b 100644 --- a/src/dbus/applicationmanager1service.h +++ b/src/dbus/applicationmanager1service.h @@ -13,7 +13,7 @@ #include #include #include "dbus/jobmanager1service.h" -#include "dbus/applicationservice.h" +#include "dbus/APPobjectmanager1adaptor.h" #include "dbus/applicationadaptor.h" #include "identifier.h" @@ -39,13 +39,25 @@ public: return false; } + if (m_applicationList.constFind(application->m_applicationPath) != m_applicationList.cend()) { + auto info = qInfo(); + info << "this application already exists."; + if (application->m_isPersistence) { + info << "desktop source:" << application->m_desktopSource.m_file.filePath(); + } + return false; + } + auto *ptr = application.data(); new ApplicationAdaptor{ptr}; - if (!registerObjectToDBus(ptr, application->m_applicationPath.path(), getDBusInterface())) { + if (!registerObjectToDBus( + ptr, application->m_applicationPath.path(), getDBusInterface(QMetaType::fromType()))) { return false; } m_applicationList.insert(application->m_applicationPath, application); + emit InterfacesAdded(application->m_applicationPath, getInterfacesListFromObject(ptr)); + return true; } void removeOneApplication(const QDBusObjectPath &application); @@ -58,6 +70,11 @@ public: public Q_SLOTS: QString Identify(const QDBusUnixFileDescriptor &pidfd, QDBusObjectPath &application, QDBusObjectPath &application_instance); void UpdateApplicationInfo(const QStringList &appIdList); + [[nodiscard]] ObjectMap GetManagedObjects() const; + +Q_SIGNALS: + void InterfacesAdded(const QDBusObjectPath &object_path, const QStringList &interfaces); + void InterfacesRemoved(const QDBusObjectPath &object_path, const QStringList &interfaces); private: std::unique_ptr m_identifier; @@ -65,4 +82,58 @@ private: QMap> m_applicationList; }; +template +QSharedPointer makeApplication(T &&source, ApplicationManager1Service *parent) +{ + static_assert(std::is_same_v or std::is_same_v, "param type must be QString or DesktopFile."); + QString objectPath; + QTextStream sourceStream; + QFile sourceFile; + QSharedPointer app{nullptr}; + + if constexpr (std::is_same_v) { + DesktopFile in{std::forward(source)}; + objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + escapeToObjectPath(in.desktopId()); + sourceFile.setFileName(in.filePath()); + + if (!sourceFile.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) { + qCritical() << "desktop file can't open:" << in.filePath() << sourceFile.errorString(); + return nullptr; + } + + app.reset(new ApplicationService{std::move(in)}); + sourceStream.setDevice(&sourceFile); + } else if (std::is_same_v) { + QString in{std::forward(source)}; + objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + QUuid::createUuid().toString(QUuid::Id128); + + app.reset(new ApplicationService{std::move(in)}); + sourceStream.setString(&in, QTextStream::ReadOnly | QTextStream::Text); + } + + std::unique_ptr entry{std::make_unique()}; + auto error = entry->parse(sourceStream); + + if (error != DesktopErrorCode::NoError) { + if (error != DesktopErrorCode::EntryKeyInvalid) { + return nullptr; + } + } + + if (auto val = entry->value(DesktopFileEntryKey, "Hidden"); val.has_value()) { + bool ok{false}; + if (auto hidden = val.value().toBoolean(ok); ok and hidden) { + return nullptr; + } + } + + app->m_parent = parent; + app->m_entry.reset(entry.release()); + app->m_applicationPath = QDBusObjectPath{std::move(objectPath)}; + + // TODO: icon lookup + new APPObjectManagerAdaptor{app.data()}; + return app; +} + #endif diff --git a/src/dbus/applicationservice.cpp b/src/dbus/applicationservice.cpp index 52f61e1..7b73744 100644 --- a/src/dbus/applicationservice.cpp +++ b/src/dbus/applicationservice.cpp @@ -206,6 +206,18 @@ QStringList ApplicationService::actions() const noexcept return actionList; } +ObjectMap ApplicationService::GetManagedObjects() const +{ + ObjectMap objs; + + for (const auto &[key, value] : m_Instances.asKeyValueRange()) { + auto interfaces = getInterfacesListFromObject(value.data()); + objs.insert(key, interfaces); + } + + return objs; +} + QString ApplicationService::id() const noexcept { if (m_isPersistence) { @@ -292,10 +304,11 @@ bool ApplicationService::addOneInstance(const QString &instanceId, const QString auto adaptor = new InstanceAdaptor(service); QString objectPath{m_applicationPath.path() + "/" + instanceId}; - if (registerObjectToDBus(service, objectPath, getDBusInterface())) { + if (registerObjectToDBus(service, objectPath, getDBusInterface(QMetaType::fromType()))) { m_Instances.insert(QDBusObjectPath{objectPath}, QSharedPointer{service}); service->moveToThread(this->thread()); adaptor->moveToThread(this->thread()); + emit InterfacesAdded(QDBusObjectPath{objectPath}, getInterfacesListFromObject(service)); return true; } @@ -306,8 +319,11 @@ bool ApplicationService::addOneInstance(const QString &instanceId, const QString void ApplicationService::removeOneInstance(const QDBusObjectPath &instance) { - unregisterObjectFromDBus(instance.path()); - m_Instances.remove(instance); + if (auto it = m_Instances.find(instance); it != m_Instances.cend()) { + emit InterfacesRemoved(instance, getInterfacesListFromObject(it->data())); + unregisterObjectFromDBus(instance.path()); + m_Instances.remove(instance); + } } void ApplicationService::removeAllInstance() diff --git a/src/dbus/applicationservice.h b/src/dbus/applicationservice.h index 1cccf57..5eb5128 100644 --- a/src/dbus/applicationservice.h +++ b/src/dbus/applicationservice.h @@ -67,6 +67,11 @@ public: public Q_SLOTS: QString GetActionName(const QString &identifier, const QStringList &env); QDBusObjectPath Launch(QString action, QStringList fields, QVariantMap options); + [[nodiscard]] ObjectMap GetManagedObjects() const; + +Q_SIGNALS: + void InterfacesAdded(const QDBusObjectPath &object_path, const QStringList &interfaces); + void InterfacesRemoved(const QDBusObjectPath &object_path, const QStringList &interfaces); private: friend class ApplicationManager1Service; @@ -118,58 +123,4 @@ private: [[nodiscard]] LaunchTask unescapeExec(const QString &str, const QStringList &fields); }; -template -QSharedPointer makeApplication(T &&source, ApplicationManager1Service *parent) -{ - static_assert(std::is_same_v or std::is_same_v, "param type must be QString or DesktopFile."); - QString objectPath; - QTextStream sourceStream; - QFile sourceFile; - QSharedPointer app{nullptr}; - - if constexpr (std::is_same_v) { - DesktopFile in{std::forward(source)}; - objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + escapeToObjectPath(in.desktopId()); - sourceFile.setFileName(in.filePath()); - - if (!sourceFile.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) { - qCritical() << "desktop file can't open:" << in.filePath() << sourceFile.errorString(); - return nullptr; - } - - app.reset(new ApplicationService{std::move(in)}); - sourceStream.setDevice(&sourceFile); - } else if (std::is_same_v) { - QString in{std::forward(source)}; - objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + QUuid::createUuid().toString(QUuid::Id128); - - app.reset(new ApplicationService{std::move(in)}); - sourceStream.setString(&in, QTextStream::ReadOnly | QTextStream::Text); - } - - std::unique_ptr entry{std::make_unique()}; - auto error = entry->parse(sourceStream); - - if (error != DesktopErrorCode::NoError) { - if (error != DesktopErrorCode::EntryKeyInvalid) { - return nullptr; - } - } - - if (auto val = entry->value(DesktopFileEntryKey, "Hidden"); val.has_value()) { - bool ok{false}; - if (auto hidden = val.value().toBoolean(ok); ok and hidden) { - return nullptr; - } - } - - app->m_parent = parent; - app->m_entry.reset(entry.release()); - app->m_applicationPath = QDBusObjectPath{std::move(objectPath)}; - - // TODO: icon lookup - - return app; -} - #endif diff --git a/src/dbus/jobmanager1service.cpp b/src/dbus/jobmanager1service.cpp index 2d7e72f..33a1533 100644 --- a/src/dbus/jobmanager1service.cpp +++ b/src/dbus/jobmanager1service.cpp @@ -9,7 +9,8 @@ JobManager1Service::JobManager1Service(ApplicationManager1Service *parent) : m_parent(parent) { new JobManager1Adaptor{this}; - if (!registerObjectToDBus(this, DDEApplicationManager1JobManagerObjectPath, getDBusInterface())) { + if (!registerObjectToDBus( + this, DDEApplicationManager1JobManagerObjectPath, getDBusInterface(QMetaType::fromType()))) { std::terminate(); } qRegisterMetaType(); diff --git a/src/dbus/jobmanager1service.h b/src/dbus/jobmanager1service.h index 23801aa..47e004d 100644 --- a/src/dbus/jobmanager1service.h +++ b/src/dbus/jobmanager1service.h @@ -61,7 +61,7 @@ public: auto *ptr = job.data(); new JobAdaptor(ptr); - if (!registerObjectToDBus(ptr, objectPath, getDBusInterface())) { + if (!registerObjectToDBus(ptr, objectPath, getDBusInterface(QMetaType::fromType()))) { qCritical() << "can't register job to dbus."; future.cancel(); return {}; diff --git a/src/global.h b/src/global.h index 49b65a9..4271cb6 100644 --- a/src/global.h +++ b/src/global.h @@ -23,6 +23,7 @@ #include "config.h" using IconMap = QMap>>; +using ObjectMap = QMap; inline QString getApplicationLauncherBinary() { @@ -185,11 +186,9 @@ private: bool registerObjectToDBus(QObject *o, const QString &path, const QString &interface); void unregisterObjectFromDBus(const QString &path); -template -QString getDBusInterface() +inline QString getDBusInterface(const QMetaType &meta) { - auto meta = QMetaType::fromType(); - auto infoObject = meta.metaObject(); + const auto *infoObject = meta.metaObject(); if (auto infoIndex = infoObject->indexOfClassInfo("D-Bus Interface"); infoIndex != -1) { return infoObject->classInfo(infoIndex).value(); } @@ -197,6 +196,19 @@ QString getDBusInterface() return {}; } +inline QStringList getInterfacesListFromObject(QObject *o) +{ + auto childs = o->children(); + QStringList interfaces; + std::for_each(childs.cbegin(), childs.cend(), [&interfaces](QObject *app) { + if (app->inherits("QDBusAbstractAdaptor")) { + interfaces.emplace_back(getDBusInterface(app->metaObject()->metaType())); + } + }); + + return interfaces; +} + inline uid_t getCurrentUID() { return getuid(); // current use linux getuid