feat: add objectManager interface
refact the way to get DBus interface from Qt Meta System Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
parent
bb83716d27
commit
d49a99d252
@ -6,7 +6,10 @@
|
||||
name="org.freedesktop.DBus.Description"
|
||||
value="Object path of the Application.
|
||||
That DBus object will impelement
|
||||
org.desktopspec.ApplicationManager1.Application."
|
||||
org.desktopspec.ApplicationManager1.Application.
|
||||
NOTE:
|
||||
If the application is uninstalled, this object path
|
||||
will be set to `/`."
|
||||
/>
|
||||
</property>
|
||||
|
||||
|
@ -30,6 +30,5 @@
|
||||
1. You should use pidfd_open(2) to get a pidfd."
|
||||
/>
|
||||
</method>
|
||||
|
||||
</interface>
|
||||
</node>
|
||||
|
19
api/dbus/org.desktopspec.ObjectManager1.xml
Normal file
19
api/dbus/org.desktopspec.ObjectManager1.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "https://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.desktopspec.DBus.ObjectManager">
|
||||
<method name="GetManagedObjects">
|
||||
<arg name="objectpath_and_interfaces" type="a{oas}" direction="out" />
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ObjectMap"/>
|
||||
</method>
|
||||
|
||||
<signal name="InterfacesAdded">
|
||||
<arg name="object_path" type="o" />
|
||||
<arg name="interfaces" type="as" />
|
||||
</signal>
|
||||
|
||||
<signal name="InterfacesRemoved">
|
||||
<arg name="object_path" type="o" />
|
||||
<arg name="interfaces" type="as" />
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
@ -15,6 +15,7 @@ void registerComplexDbusType()
|
||||
qDBusRegisterMetaType<QMap<QString, QDBusUnixFileDescriptor>>();
|
||||
qDBusRegisterMetaType<QMap<uint, QMap<QString, QDBusUnixFileDescriptor>>>();
|
||||
qDBusRegisterMetaType<IconMap>();
|
||||
qDBusRegisterMetaType<ObjectMap>();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
@ -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}
|
||||
|
@ -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 <QFile>
|
||||
#include <unistd.h>
|
||||
@ -17,8 +18,14 @@ ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr<Identifie
|
||||
}
|
||||
|
||||
new ApplicationManager1Adaptor{this};
|
||||
auto *tmp = new AMObjectManagerAdaptor{this};
|
||||
|
||||
if (!registerObjectToDBus(this, DDEApplicationManager1ObjectPath, getDBusInterface<ApplicationManager1Adaptor>())) {
|
||||
if (tmp == nullptr) {
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
if (!registerObjectToDBus(
|
||||
this, DDEApplicationManager1ObjectPath, getDBusInterface(QMetaType::fromType<ApplicationManager1Adaptor>()))) {
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
@ -98,6 +105,7 @@ QList<QDBusObjectPath> 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;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include <memory>
|
||||
#include <QMap>
|
||||
#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<ApplicationAdaptor>())) {
|
||||
if (!registerObjectToDBus(
|
||||
ptr, application->m_applicationPath.path(), getDBusInterface(QMetaType::fromType<ApplicationAdaptor>()))) {
|
||||
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<Identifier> m_identifier;
|
||||
@ -65,4 +82,58 @@ private:
|
||||
QMap<QDBusObjectPath, QSharedPointer<ApplicationService>> m_applicationList;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
QSharedPointer<ApplicationService> makeApplication(T &&source, ApplicationManager1Service *parent)
|
||||
{
|
||||
static_assert(std::is_same_v<T, DesktopFile> or std::is_same_v<T, QString>, "param type must be QString or DesktopFile.");
|
||||
QString objectPath;
|
||||
QTextStream sourceStream;
|
||||
QFile sourceFile;
|
||||
QSharedPointer<ApplicationService> app{nullptr};
|
||||
|
||||
if constexpr (std::is_same_v<T, DesktopFile>) {
|
||||
DesktopFile in{std::forward<T>(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<T, QString>) {
|
||||
QString in{std::forward<T>(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<DesktopEntry> entry{std::make_unique<DesktopEntry>()};
|
||||
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
|
||||
|
@ -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<InstanceAdaptor>())) {
|
||||
if (registerObjectToDBus(service, objectPath, getDBusInterface(QMetaType::fromType<InstanceAdaptor>()))) {
|
||||
m_Instances.insert(QDBusObjectPath{objectPath}, QSharedPointer<InstanceService>{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)
|
||||
{
|
||||
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()
|
||||
|
@ -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 <typename T>
|
||||
QSharedPointer<ApplicationService> makeApplication(T &&source, ApplicationManager1Service *parent)
|
||||
{
|
||||
static_assert(std::is_same_v<T, DesktopFile> or std::is_same_v<T, QString>, "param type must be QString or DesktopFile.");
|
||||
QString objectPath;
|
||||
QTextStream sourceStream;
|
||||
QFile sourceFile;
|
||||
QSharedPointer<ApplicationService> app{nullptr};
|
||||
|
||||
if constexpr (std::is_same_v<T, DesktopFile>) {
|
||||
DesktopFile in{std::forward<T>(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<T, QString>) {
|
||||
QString in{std::forward<T>(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<DesktopEntry> entry{std::make_unique<DesktopEntry>()};
|
||||
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
|
||||
|
@ -9,7 +9,8 @@ JobManager1Service::JobManager1Service(ApplicationManager1Service *parent)
|
||||
: m_parent(parent)
|
||||
{
|
||||
new JobManager1Adaptor{this};
|
||||
if (!registerObjectToDBus(this, DDEApplicationManager1JobManagerObjectPath, getDBusInterface<JobManager1Adaptor>())) {
|
||||
if (!registerObjectToDBus(
|
||||
this, DDEApplicationManager1JobManagerObjectPath, getDBusInterface(QMetaType::fromType<JobManager1Adaptor>()))) {
|
||||
std::terminate();
|
||||
}
|
||||
qRegisterMetaType<LaunchTask>();
|
||||
|
@ -61,7 +61,7 @@ public:
|
||||
|
||||
auto *ptr = job.data();
|
||||
new JobAdaptor(ptr);
|
||||
if (!registerObjectToDBus(ptr, objectPath, getDBusInterface<JobAdaptor>())) {
|
||||
if (!registerObjectToDBus(ptr, objectPath, getDBusInterface(QMetaType::fromType<JobAdaptor>()))) {
|
||||
qCritical() << "can't register job to dbus.";
|
||||
future.cancel();
|
||||
return {};
|
||||
|
20
src/global.h
20
src/global.h
@ -23,6 +23,7 @@
|
||||
#include "config.h"
|
||||
|
||||
using IconMap = QMap<QString, QMap<uint, QMap<QString, QDBusUnixFileDescriptor>>>;
|
||||
using ObjectMap = QMap<QDBusObjectPath, QStringList>;
|
||||
|
||||
inline QString getApplicationLauncherBinary()
|
||||
{
|
||||
@ -185,11 +186,9 @@ private:
|
||||
bool registerObjectToDBus(QObject *o, const QString &path, const QString &interface);
|
||||
void unregisterObjectFromDBus(const QString &path);
|
||||
|
||||
template <typename T>
|
||||
QString getDBusInterface()
|
||||
inline QString getDBusInterface(const QMetaType &meta)
|
||||
{
|
||||
auto meta = QMetaType::fromType<T>();
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user