feat: support application hooks

Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
ComixHe
2023-10-07 15:15:08 +08:00
committed by Comix
parent f233279466
commit fb0fc0a8ee
13 changed files with 317 additions and 56 deletions

View File

@ -7,6 +7,7 @@
#include "dbus/AMobjectmanager1adaptor.h"
#include "systemdsignaldispatcher.h"
#include "propertiesForwarder.h"
#include "applicationHooks.h"
#include <QFile>
#include <QDBusMessage>
#include <unistd.h>
@ -70,6 +71,8 @@ void ApplicationManager1Service::initService(QDBusConnection &connection) noexce
scanInstances();
loadHooks();
if (auto *ptr = new (std::nothrow) PropertiesForwarder{DDEApplicationManager1ObjectPath, this}; ptr == nullptr) {
qCritical() << "new PropertiesForwarder of Application Manager failed.";
}
@ -209,18 +212,23 @@ void ApplicationManager1Service::scanApplications() noexcept
{
const auto &desktopFileDirs = getDesktopFileDirs();
applyIteratively(QList<QDir>(desktopFileDirs.cbegin(), desktopFileDirs.cend()), [this](const QFileInfo &info) -> bool {
DesktopErrorCode err{DesktopErrorCode::NoError};
auto ret = DesktopFile::searchDesktopFileByPath(info.absoluteFilePath(), err);
if (!ret.has_value()) {
qWarning() << "failed to search File:" << err;
return false;
}
if (!this->addApplication(std::move(ret).value())) {
qWarning() << "add Application failed, skip...";
}
return false; // means to apply this function to the rest of the files
});
applyIteratively(
QList<QDir>(desktopFileDirs.cbegin(), desktopFileDirs.cend()),
[this](const QFileInfo &info) -> bool {
DesktopErrorCode err{DesktopErrorCode::NoError};
auto ret = DesktopFile::searchDesktopFileByPath(info.absoluteFilePath(), err);
if (!ret.has_value()) {
qWarning() << "failed to search File:" << err;
return false;
}
if (!this->addApplication(std::move(ret).value())) {
qWarning() << "add Application failed, skip...";
}
return false; // means to apply this function to the rest of the files
},
QDir::Readable | QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot,
{"*.desktop"},
QDir::Name | QDir::DirsLast);
}
void ApplicationManager1Service::scanInstances() noexcept
@ -250,12 +258,17 @@ void ApplicationManager1Service::scanAutoStart() noexcept
{
auto autostartDirs = getAutoStartDirs();
QStringList needToLaunch;
applyIteratively(QList<QDir>{autostartDirs.cbegin(), autostartDirs.cend()}, [&needToLaunch](const QFileInfo &info) {
if (info.isSymbolicLink()) {
needToLaunch.emplace_back(info.symLinkTarget());
}
return false;
});
applyIteratively(
QList<QDir>{autostartDirs.cbegin(), autostartDirs.cend()},
[&needToLaunch](const QFileInfo &info) {
if (info.isSymbolicLink()) {
needToLaunch.emplace_back(info.symLinkTarget());
}
return false;
},
QDir::Readable | QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot,
{"*.desktop"},
QDir::Name | QDir::DirsLast);
while (!needToLaunch.isEmpty()) {
const auto &filePath = needToLaunch.takeFirst();
@ -269,6 +282,32 @@ void ApplicationManager1Service::scanAutoStart() noexcept
}
}
void ApplicationManager1Service::loadHooks() noexcept
{
auto hookDirs = getXDGDataDirs();
std::for_each(hookDirs.begin(), hookDirs.end(), [](QString &str) { str.append(ApplicationManagerHookDir); });
QHash<QString, ApplicationHook> hooks;
applyIteratively(
QList<QDir>(hookDirs.begin(), hookDirs.end()),
[&hooks](const QFileInfo &info) -> bool {
auto fileName = info.fileName();
if (!hooks.contains(fileName)) {
if (auto hook = ApplicationHook::loadFromFile(info.absoluteFilePath()); hook) {
hooks.insert(fileName, std::move(hook).value());
}
}
return false;
},
QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::Readable,
{"*.json"},
QDir::Name);
auto hookList = hooks.values();
std::sort(hookList.begin(), hookList.end());
m_hookElements = generateHooks(hookList);
}
QList<QDBusObjectPath> ApplicationManager1Service::list() const
{
return m_applicationList.keys();
@ -433,34 +472,39 @@ void ApplicationManager1Service::ReloadApplications()
auto apps = m_applicationList.keys();
applyIteratively(QList<QDir>(desktopFileDirs.cbegin(), desktopFileDirs.cend()), [this, &apps](const QFileInfo &info) -> bool {
DesktopErrorCode err{DesktopErrorCode::NoError};
auto ret = DesktopFile::searchDesktopFileByPath(info.absoluteFilePath(), err);
if (!ret.has_value()) {
applyIteratively(
QList<QDir>(desktopFileDirs.cbegin(), desktopFileDirs.cend()),
[this, &apps](const QFileInfo &info) -> bool {
DesktopErrorCode err{DesktopErrorCode::NoError};
auto ret = DesktopFile::searchDesktopFileByPath(info.absoluteFilePath(), err);
if (!ret.has_value()) {
return false;
}
auto file = std::move(ret).value();
auto destApp =
std::find_if(m_applicationList.cbegin(),
m_applicationList.cend(),
[&file](const QSharedPointer<ApplicationService> &app) { return file.desktopId() == app->id(); });
if (err != DesktopErrorCode::NoError) {
qWarning() << "error occurred:" << err << " skip this application.";
return false;
}
if (destApp != m_applicationList.cend() and apps.contains(destApp.key())) {
apps.removeOne(destApp.key());
updateApplication(destApp.value(), std::move(file));
return false;
}
addApplication(std::move(file));
return false;
}
auto file = std::move(ret).value();
auto destApp =
std::find_if(m_applicationList.cbegin(),
m_applicationList.cend(),
[&file](const QSharedPointer<ApplicationService> &app) { return file.desktopId() == app->id(); });
if (err != DesktopErrorCode::NoError) {
qWarning() << "error occurred:" << err << " skip this application.";
return false;
}
if (destApp != m_applicationList.cend() and apps.contains(destApp.key())) {
apps.removeOne(destApp.key());
updateApplication(destApp.value(), std::move(file));
return false;
}
addApplication(std::move(file));
return false;
});
},
QDir::Readable | QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot,
{"*.desktop"},
QDir::Name | QDir::DirsLast);
for (const auto &key : apps) {
removeOneApplication(key);

View File

@ -41,7 +41,9 @@ public:
void updateApplication(const QSharedPointer<ApplicationService> &destApp, DesktopFile desktopFile) noexcept;
JobManager1Service &jobManager() noexcept { return *m_jobManager; }
[[nodiscard]] JobManager1Service &jobManager() noexcept { return *m_jobManager; }
[[nodiscard]] const JobManager1Service &jobManager() const noexcept { return *m_jobManager; }
[[nodiscard]] const QStringList &applicationHooks() const noexcept { return m_hookElements; }
public Q_SLOTS:
QString Identify(const QDBusUnixFileDescriptor &pidfd,
@ -59,11 +61,13 @@ private:
std::unique_ptr<Identifier> m_identifier;
std::weak_ptr<ApplicationManager1Storage> m_storage;
QScopedPointer<JobManager1Service> m_jobManager{nullptr};
QStringList m_hookElements;
QMap<QDBusObjectPath, QSharedPointer<ApplicationService>> m_applicationList;
void scanApplications() noexcept;
void scanInstances() noexcept;
void scanAutoStart() noexcept;
void loadHooks() noexcept;
void addInstanceToApplication(const QString &unitName, const QDBusObjectPath &systemdUnitPath);
void removeInstanceFromApplication(const QString &unitName, const QDBusObjectPath &systemdUnitPath);
};

View File

@ -180,6 +180,10 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL
}
}
optionsMap.remove("_hooks"); // this is internal property, user shouldn't pass it to Application Manager
if (const auto &hooks = parent()->applicationHooks(); !hooks.isEmpty()) {
optionsMap.insert("_hooks", hooks);
}
auto cmds = generateCommand(optionsMap);
auto [bin, execCmds, res] = unescapeExec(execStr, fields);
@ -190,7 +194,7 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL
}
cmds.append(std::move(execCmds));
auto &jobManager = static_cast<ApplicationManager1Service *>(parent())->jobManager();
auto &jobManager = parent()->jobManager();
return jobManager.addJob(
m_applicationPath.path(),
[this, binary = std::move(bin), commands = std::move(cmds)](const QVariant &variantValue) mutable -> QVariant {

View File

@ -18,6 +18,7 @@
#include <memory>
#include <utility>
#include "applicationmanagerstorage.h"
#include "dbus/applicationmanager1service.h"
#include "dbus/instanceservice.h"
#include "global.h"
#include "desktopentry.h"
@ -151,6 +152,11 @@ private:
void updateAfterLaunch(bool isLaunch) noexcept;
static bool shouldBeShown(const std::unique_ptr<DesktopEntry> &entry) noexcept;
[[nodiscard]] bool autostartCheck(const QString &linkPath) const noexcept;
[[nodiscard]] ApplicationManager1Service *parent() { return dynamic_cast<ApplicationManager1Service *>(QObject::parent()); }
[[nodiscard]] const ApplicationManager1Service *parent() const
{
return dynamic_cast<ApplicationManager1Service *>(QObject::parent());
}
};
#endif