feat: support application hooks
Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
@ -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);
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user