refact: ApplicationService ctor and some member functions
Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
parent
0e7d84f61d
commit
920594d6e5
@ -6,6 +6,7 @@
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <systemd/sd-journal.h>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
@ -73,6 +74,12 @@ ExitCode fromString(const char *str)
|
||||
int processExecStart(msg_ptr &msg, const std::deque<std::string_view> &execArgs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ret = sd_bus_message_open_container(msg, SD_BUS_TYPE_STRUCT, "sv"); ret < 0) {
|
||||
sd_journal_perror("open struct of ExecStart failed.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret = sd_bus_message_append(msg, "s", "ExecStart"); ret < 0) {
|
||||
sd_journal_perror("append ExecStart failed.");
|
||||
return ret;
|
||||
@ -138,6 +145,11 @@ int processExecStart(msg_ptr &msg, const std::deque<std::string_view> &execArgs)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret = sd_bus_message_close_container(msg); ret < 0) {
|
||||
sd_journal_perror("close struct of execStart failed.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -146,18 +158,19 @@ int processKVPair(msg_ptr &msg, const std::map<std::string_view, std::string_vie
|
||||
int ret;
|
||||
if (!props.empty()) {
|
||||
for (auto [key, value] : props) {
|
||||
// NOTE: append if necessary
|
||||
// usage:
|
||||
// sd_bus_message_append(msg,"s",key.data());
|
||||
// sd_bus_message_open_container(msg,SD_BUS_TYPE_VARIANT,"[corresponding type]");
|
||||
// append content....
|
||||
// sd_bus_message_close_container(msg);
|
||||
std::string keyStr{key};
|
||||
std::string valueStr{value};
|
||||
ret = sd_bus_message_append(msg, "(sv)", keyStr.data(), "s", valueStr.data());
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> &&cmdLines)
|
||||
std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> cmdLines)
|
||||
{
|
||||
std::string serviceName{"internalError"};
|
||||
std::map<std::string_view, std::string_view> props;
|
||||
@ -176,7 +189,7 @@ std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> &&cmdLines)
|
||||
|
||||
auto kvStr = str.substr(2);
|
||||
if (!kvStr.empty()) [[likely]] {
|
||||
auto it = kvStr.cbegin();
|
||||
const auto *it = kvStr.cbegin();
|
||||
if (it = std::find(it, kvStr.cend(), '='); it == kvStr.cend()) {
|
||||
sd_journal_print(LOG_WARNING, "invalid k-v pair: %s", kvStr.data());
|
||||
cmdLines.pop_front();
|
||||
@ -248,11 +261,6 @@ std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> &&cmdLines)
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
if (ret = sd_bus_message_open_container(msg, SD_BUS_TYPE_STRUCT, "sv"); ret < 0) {
|
||||
sd_journal_perror("open struct failed.");
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
if (ret = processKVPair(msg, props); ret < 0) { // process props
|
||||
serviceName = "invalidInput";
|
||||
return serviceName;
|
||||
@ -263,10 +271,6 @@ std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> &&cmdLines)
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
if (ret = sd_bus_message_close_container(msg); ret < 0) {
|
||||
sd_journal_perror("close struct failed.");
|
||||
return serviceName;
|
||||
}
|
||||
if (ret = sd_bus_message_close_container(msg); ret < 0) {
|
||||
sd_journal_perror("close array failed.");
|
||||
return serviceName;
|
||||
|
@ -44,5 +44,5 @@ int main(int argc, char *argv[])
|
||||
return false; // means to apply this function to the rest of the files
|
||||
});
|
||||
|
||||
return app.exec();
|
||||
return QCoreApplication::exec();
|
||||
}
|
||||
|
@ -53,10 +53,9 @@ ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr<Identifie
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &appRef = *appIt;
|
||||
const auto &applicationPath = appRef->m_applicationPath.path();
|
||||
const auto &applicationPath = (*appIt)->applicationPath().path();
|
||||
|
||||
if (!appRef->addOneInstance(instanceId, applicationPath, systemdUnitPath.path())) [[likely]] {
|
||||
if (!(*appIt)->addOneInstance(instanceId, applicationPath, systemdUnitPath.path())) [[likely]] {
|
||||
qCritical() << "add Instance failed:" << applicationPath << unitName << systemdUnitPath.path();
|
||||
}
|
||||
|
||||
@ -83,16 +82,15 @@ ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr<Identifie
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &appRef = *appIt;
|
||||
const auto &appIns = (*appIt)->applicationInstances();
|
||||
|
||||
auto instanceIt = std::find_if(appRef->m_Instances.cbegin(),
|
||||
appRef->m_Instances.cend(),
|
||||
[&systemdUnitPath](const QSharedPointer<InstanceService> &value) {
|
||||
auto instanceIt = std::find_if(
|
||||
appIns.cbegin(), appIns.cend(), [&systemdUnitPath](const QSharedPointer<InstanceService> &value) {
|
||||
return value->systemdUnitPath() == systemdUnitPath;
|
||||
});
|
||||
|
||||
if (instanceIt != appRef->m_Instances.cend()) [[likely]] {
|
||||
appRef->removeOneInstance(instanceIt.key());
|
||||
if (instanceIt != appIns.cend()) [[likely]] {
|
||||
(*appIt)->removeOneInstance(instanceIt.key());
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -102,7 +100,41 @@ QList<QDBusObjectPath> ApplicationManager1Service::list() const
|
||||
return m_applicationList.keys();
|
||||
}
|
||||
|
||||
void ApplicationManager1Service::removeOneApplication(const QDBusObjectPath &application)
|
||||
bool ApplicationManager1Service::addApplication(DesktopFile desktopFileSource) noexcept
|
||||
{
|
||||
QSharedPointer<ApplicationService> application =
|
||||
ApplicationService::createApplicationService(std::move(desktopFileSource), this);
|
||||
if (!application) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_applicationList.constFind(application->applicationPath()) != m_applicationList.cend()) {
|
||||
auto info = qInfo();
|
||||
info << "this application already exists.";
|
||||
if (application->desktopFileSource().persistence()) {
|
||||
info << "desktop source:" << application->desktopFileSource().fileSource();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *ptr = application.data();
|
||||
|
||||
if (auto *adaptor = new (std::nothrow) ApplicationAdaptor{ptr}; adaptor == nullptr) {
|
||||
qCritical() << "new ApplicationAdaptor failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!registerObjectToDBus(
|
||||
ptr, application->applicationPath().path(), getDBusInterface(QMetaType::fromType<ApplicationAdaptor>()))) {
|
||||
return false;
|
||||
}
|
||||
m_applicationList.insert(application->applicationPath(), application);
|
||||
emit InterfacesAdded(application->applicationPath(), getInterfacesListFromObject(ptr));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ApplicationManager1Service::removeOneApplication(const QDBusObjectPath &application) noexcept
|
||||
{
|
||||
if (auto it = m_applicationList.find(application); it != m_applicationList.cend()) {
|
||||
emit InterfacesRemoved(application, getInterfacesListFromObject(it->data()));
|
||||
@ -111,7 +143,7 @@ void ApplicationManager1Service::removeOneApplication(const QDBusObjectPath &app
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationManager1Service::removeAllApplication()
|
||||
void ApplicationManager1Service::removeAllApplication() noexcept
|
||||
{
|
||||
for (const auto &app : m_applicationList.keys()) {
|
||||
removeOneApplication(app);
|
||||
@ -173,8 +205,12 @@ QString ApplicationManager1Service::Identify(const QDBusUnixFileDescriptor &pidf
|
||||
void ApplicationManager1Service::updateApplication(const QSharedPointer<ApplicationService> &destApp,
|
||||
const DesktopFile &desktopFile) noexcept
|
||||
{
|
||||
if (auto app = m_applicationList.find(destApp->applicationPath()); app == m_applicationList.cend()) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct stat buf;
|
||||
const auto *filePath = desktopFile.filePath().toLocal8Bit().data();
|
||||
const auto *filePath = desktopFile.fileSource().toLocal8Bit().data();
|
||||
if (auto ret = stat(filePath, &buf); ret == -1) {
|
||||
qWarning() << "get file" << filePath << "state failed:" << std::strerror(errno);
|
||||
return;
|
||||
@ -182,14 +218,19 @@ void ApplicationManager1Service::updateApplication(const QSharedPointer<Applicat
|
||||
|
||||
constexpr std::size_t secToNano = 1e9;
|
||||
|
||||
if (destApp->m_desktopSource.m_file.modified(buf.st_mtim.tv_sec * secToNano + buf.st_mtim.tv_nsec)) {
|
||||
auto newEntry = new DesktopEntry{};
|
||||
auto err = newEntry->parse(destApp->m_desktopSource.m_file);
|
||||
if (destApp->desktopFileSource().modified(buf.st_mtim.tv_sec * secToNano + buf.st_mtim.tv_nsec)) {
|
||||
auto *newEntry = new (std::nothrow) DesktopEntry{};
|
||||
if (newEntry == nullptr) {
|
||||
qCritical() << "new DesktopEntry failed.";
|
||||
return;
|
||||
}
|
||||
|
||||
auto err = newEntry->parse(destApp->desktopFileSource());
|
||||
if (err != DesktopErrorCode::NoError and err != DesktopErrorCode::EntryKeyInvalid) {
|
||||
qWarning() << "update desktop file failed:" << err << ", content wouldn't change.";
|
||||
return;
|
||||
}
|
||||
destApp->m_entry.reset(newEntry);
|
||||
destApp->resetEntry(newEntry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,39 +31,11 @@ public:
|
||||
Q_PROPERTY(QList<QDBusObjectPath> List READ list)
|
||||
[[nodiscard]] QList<QDBusObjectPath> list() const;
|
||||
|
||||
template <typename T>
|
||||
bool addApplication(T &&desktopFileSource)
|
||||
{
|
||||
QSharedPointer<ApplicationService> application = makeApplication(std::forward<T>(desktopFileSource), this);
|
||||
if (!application) {
|
||||
return false;
|
||||
}
|
||||
bool addApplication(DesktopFile desktopFileSource) noexcept;
|
||||
void removeOneApplication(const QDBusObjectPath &application) noexcept;
|
||||
void removeAllApplication() noexcept;
|
||||
|
||||
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(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);
|
||||
void removeAllApplication();
|
||||
|
||||
void updateApplication(const QSharedPointer<ApplicationService> &deskApp, const DesktopFile &desktopFile) noexcept;
|
||||
void updateApplication(const QSharedPointer<ApplicationService> &destApp, const DesktopFile &desktopFile) noexcept;
|
||||
|
||||
JobManager1Service &jobManager() noexcept { return *m_jobManager; }
|
||||
|
||||
@ -82,59 +54,4 @@ private:
|
||||
QMap<QDBusObjectPath, QSharedPointer<ApplicationService>> m_applicationList;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
QSharedPointer<ApplicationService> makeApplication(T &&source,
|
||||
ApplicationManager1Service *parent) // NOTE: maybe we should refactor
|
||||
{
|
||||
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
|
||||
|
@ -13,10 +13,16 @@
|
||||
#include <QRegularExpression>
|
||||
#include <QProcess>
|
||||
#include <algorithm>
|
||||
#include <new>
|
||||
|
||||
ApplicationService::ApplicationService(DesktopFile source, ApplicationManager1Service *parent)
|
||||
: QObject(parent)
|
||||
, m_desktopSource(std::move(source))
|
||||
{
|
||||
}
|
||||
|
||||
ApplicationService::~ApplicationService()
|
||||
{
|
||||
m_desktopSource.destruct(m_isPersistence);
|
||||
for (auto &instance : m_Instances.values()) {
|
||||
instance->m_Application = QDBusObjectPath{"/"};
|
||||
auto *ptr = instance.get();
|
||||
@ -25,6 +31,55 @@ ApplicationService::~ApplicationService()
|
||||
}
|
||||
}
|
||||
|
||||
QSharedPointer<ApplicationService> ApplicationService::createApplicationService(DesktopFile source,
|
||||
ApplicationManager1Service *parent) noexcept
|
||||
{
|
||||
QString objectPath;
|
||||
QTextStream sourceStream;
|
||||
QFile sourceFile;
|
||||
QString tempSource;
|
||||
QSharedPointer<ApplicationService> app{nullptr};
|
||||
|
||||
if (source.persistence()) {
|
||||
objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + escapeToObjectPath(source.desktopId());
|
||||
sourceFile.setFileName(source.fileSource());
|
||||
if (!sourceFile.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) {
|
||||
qCritical() << "desktop file can't open:" << source.fileSource() << sourceFile.errorString();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
app.reset(new (std::nothrow) ApplicationService{std::move(source), parent});
|
||||
sourceStream.setDevice(&sourceFile);
|
||||
} else {
|
||||
tempSource = source.fileSource();
|
||||
objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + QUuid::createUuid().toString(QUuid::Id128);
|
||||
app.reset(new (std::nothrow) ApplicationService{std::move(source), parent});
|
||||
sourceStream.setString(&tempSource, 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_entry.reset(entry.release());
|
||||
app->m_applicationPath = QDBusObjectPath{std::move(objectPath)};
|
||||
|
||||
// TODO: icon lookup
|
||||
new (std::nothrow) APPObjectManagerAdaptor{app.data()};
|
||||
return app;
|
||||
}
|
||||
|
||||
QString ApplicationService::GetActionName(const QString &identifier, const QStringList &env) const
|
||||
{
|
||||
const auto &supportedActions = actions();
|
||||
@ -129,7 +184,7 @@ QString ApplicationService::GetIconName(const QString &action) const
|
||||
return ok ? name : "";
|
||||
}
|
||||
|
||||
QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, QVariantMap options)
|
||||
QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringList &fields, const QVariantMap &options)
|
||||
{
|
||||
QString execStr;
|
||||
bool ok;
|
||||
@ -189,7 +244,7 @@ QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, Q
|
||||
|
||||
cmds.prepend("--");
|
||||
|
||||
auto &jobManager = m_parent->jobManager();
|
||||
auto &jobManager = static_cast<ApplicationManager1Service *>(parent())->jobManager();
|
||||
|
||||
return jobManager.addJob(
|
||||
m_applicationPath.path(),
|
||||
@ -198,6 +253,10 @@ QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, Q
|
||||
auto instanceRandomUUID = QUuid::createUuid().toString(QUuid::Id128);
|
||||
auto objectPath = m_applicationPath.path() + "/" + instanceRandomUUID;
|
||||
|
||||
if (m_desktopSource.persistence()) {
|
||||
commands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.fileSource()));
|
||||
}
|
||||
|
||||
if (resourceFile.isEmpty()) {
|
||||
commands.push_front(QString{R"(--unitName=app-DDE-%1@%2.service)"}.arg(
|
||||
escapeApplicationId(this->id()), instanceRandomUUID)); // launcher should use this instanceId
|
||||
@ -211,7 +270,7 @@ QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, Q
|
||||
return objectPath;
|
||||
}
|
||||
|
||||
int location{0};
|
||||
qsizetype location{0};
|
||||
location = commands.indexOf(R"(%f)");
|
||||
if (location != -1) { // due to std::move, there only remove once
|
||||
commands.remove(location);
|
||||
@ -225,16 +284,15 @@ QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, Q
|
||||
}
|
||||
}
|
||||
|
||||
// resourceFile must be available in the following contexts
|
||||
auto tmp = commands;
|
||||
tmp.insert(location, resourceFile);
|
||||
tmp.push_front(QString{R"(--unitName=DDE-%1@%2.service)"}.arg(this->id(), instanceRandomUUID));
|
||||
// NOTE: resourceFile must be available in the following contexts
|
||||
commands.insert(location, resourceFile);
|
||||
commands.push_front(QString{R"(--unitName=DDE-%1@%2.service)"}.arg(this->id(), instanceRandomUUID));
|
||||
QProcess process;
|
||||
process.start(getApplicationLauncherBinary(), tmp);
|
||||
process.start(getApplicationLauncherBinary(), commands);
|
||||
process.waitForFinished();
|
||||
auto exitCode = process.exitCode();
|
||||
if (exitCode != 0) {
|
||||
qWarning() << "Launch Application Failed:" << binary << tmp;
|
||||
qWarning() << "Launch Application Failed:" << binary << commands;
|
||||
return QString{""};
|
||||
}
|
||||
return objectPath;
|
||||
@ -245,7 +303,7 @@ QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, Q
|
||||
QStringList ApplicationService::actions() const noexcept
|
||||
{
|
||||
if (m_entry.isNull()) {
|
||||
qWarning() << "desktop entry is empty, isPersistence:" << m_isPersistence;
|
||||
qWarning() << "desktop entry is empty, isPersistence:" << m_desktopSource.persistence();
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -274,8 +332,8 @@ ObjectMap ApplicationService::GetManagedObjects() const
|
||||
|
||||
QString ApplicationService::id() const noexcept
|
||||
{
|
||||
if (m_isPersistence) {
|
||||
return m_desktopSource.m_file.desktopId();
|
||||
if (m_desktopSource.persistence()) {
|
||||
return m_desktopSource.desktopId();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@ -310,8 +368,8 @@ QList<QDBusObjectPath> ApplicationService::instances() const noexcept
|
||||
|
||||
bool ApplicationService::addOneInstance(const QString &instanceId, const QString &application, const QString &systemdUnitPath)
|
||||
{
|
||||
auto service = new InstanceService{instanceId, application, systemdUnitPath};
|
||||
auto adaptor = new InstanceAdaptor(service);
|
||||
auto *service = new InstanceService{instanceId, application, systemdUnitPath};
|
||||
auto *adaptor = new InstanceAdaptor(service);
|
||||
QString objectPath{m_applicationPath.path() + "/" + instanceId};
|
||||
|
||||
if (registerObjectToDBus(service, objectPath, getDBusInterface(QMetaType::fromType<InstanceAdaptor>()))) {
|
||||
@ -327,7 +385,7 @@ bool ApplicationService::addOneInstance(const QString &instanceId, const QString
|
||||
return false;
|
||||
}
|
||||
|
||||
void ApplicationService::removeOneInstance(const QDBusObjectPath &instance)
|
||||
void ApplicationService::removeOneInstance(const QDBusObjectPath &instance) noexcept
|
||||
{
|
||||
if (auto it = m_Instances.find(instance); it != m_Instances.cend()) {
|
||||
emit InterfacesRemoved(instance, getInterfacesListFromObject(it->data()));
|
||||
@ -336,7 +394,7 @@ void ApplicationService::removeOneInstance(const QDBusObjectPath &instance)
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationService::removeAllInstance()
|
||||
void ApplicationService::removeAllInstance() noexcept
|
||||
{
|
||||
for (const auto &instance : m_Instances.keys()) {
|
||||
removeOneInstance(instance);
|
||||
@ -353,9 +411,14 @@ QDBusObjectPath ApplicationService::findInstance(const QString &instanceId) cons
|
||||
return {};
|
||||
}
|
||||
|
||||
void ApplicationService::resetEntry(DesktopEntry *newEntry) noexcept
|
||||
{
|
||||
m_entry.reset(newEntry);
|
||||
}
|
||||
|
||||
QString ApplicationService::userNameLookup(uid_t uid)
|
||||
{
|
||||
auto pws = getpwuid(uid);
|
||||
auto *pws = getpwuid(uid);
|
||||
return pws->pw_name;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <QTextStream>
|
||||
#include <QFile>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include "dbus/instanceservice.h"
|
||||
#include "global.h"
|
||||
#include "desktopentry.h"
|
||||
@ -54,13 +55,20 @@ public:
|
||||
void setLauncher(const QString &launcher) noexcept { m_launcher = launcher; }
|
||||
|
||||
bool addOneInstance(const QString &instanceId, const QString &application, const QString &systemdUnitPath);
|
||||
void recoverInstances(const QList<QDBusObjectPath>) noexcept;
|
||||
void removeOneInstance(const QDBusObjectPath &instance);
|
||||
void removeAllInstance();
|
||||
void recoverInstances(const QList<QDBusObjectPath> &instanceList) noexcept;
|
||||
void removeOneInstance(const QDBusObjectPath &instance) noexcept;
|
||||
void removeAllInstance() noexcept;
|
||||
[[nodiscard]] const QDBusObjectPath &applicationPath() const noexcept { return m_applicationPath; }
|
||||
[[nodiscard]] const DesktopFile &desktopFileSource() const noexcept { return m_desktopSource; }
|
||||
[[nodiscard]] const QMap<QDBusObjectPath, QSharedPointer<InstanceService>> &applicationInstances() const noexcept
|
||||
{
|
||||
return m_Instances;
|
||||
}
|
||||
void resetEntry(DesktopEntry *newEntry) noexcept;
|
||||
|
||||
public Q_SLOTS:
|
||||
[[nodiscard]] QString GetActionName(const QString &identifier, const QStringList &env) const;
|
||||
QDBusObjectPath Launch(QString action, QStringList fields, QVariantMap options);
|
||||
QDBusObjectPath Launch(const QString &action, const QStringList &fields, const QVariantMap &options);
|
||||
[[nodiscard]] QString GetIconName(const QString &action) const;
|
||||
[[nodiscard]] QString GetDisplayName(const QStringList &env) const;
|
||||
[[nodiscard]] ObjectMap GetManagedObjects() const;
|
||||
@ -71,51 +79,17 @@ Q_SIGNALS:
|
||||
|
||||
private:
|
||||
friend class ApplicationManager1Service;
|
||||
template <typename T>
|
||||
friend QSharedPointer<ApplicationService> makeApplication(T &&source, ApplicationManager1Service *parent);
|
||||
|
||||
template <typename T>
|
||||
explicit ApplicationService(T &&source)
|
||||
: m_isPersistence(static_cast<bool>(std::is_same_v<T, DesktopFile>))
|
||||
, m_desktopSource(std::forward<T>(source))
|
||||
{
|
||||
}
|
||||
|
||||
explicit ApplicationService(DesktopFile source, ApplicationManager1Service *parent);
|
||||
static QSharedPointer<ApplicationService> createApplicationService(DesktopFile source,
|
||||
ApplicationManager1Service *parent) noexcept;
|
||||
bool m_AutoStart{false};
|
||||
bool m_isPersistence;
|
||||
ApplicationManager1Service *m_parent{nullptr};
|
||||
QDBusObjectPath m_applicationPath;
|
||||
QString m_launcher{getApplicationLauncherBinary()};
|
||||
union DesktopSource
|
||||
{
|
||||
template <typename T, std::enable_if_t<std::is_same_v<T, DesktopFile>, bool> = true>
|
||||
DesktopSource(T &&source)
|
||||
: m_file(std::forward<T>(source))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_same_v<T, QString>, bool> = true>
|
||||
DesktopSource(T &&source)
|
||||
: m_temp(std::forward<T>(source))
|
||||
{
|
||||
}
|
||||
|
||||
void destruct(bool isPersistence)
|
||||
{
|
||||
if (isPersistence) {
|
||||
m_file.~DesktopFile();
|
||||
} else {
|
||||
m_temp.~QString();
|
||||
}
|
||||
}
|
||||
~DesktopSource(){};
|
||||
QString m_temp;
|
||||
DesktopFile m_file;
|
||||
} m_desktopSource;
|
||||
DesktopFile m_desktopSource;
|
||||
QSharedPointer<DesktopEntry> m_entry{nullptr};
|
||||
QSharedPointer<DesktopIcons> m_Icons{nullptr};
|
||||
QMap<QDBusObjectPath, QSharedPointer<InstanceService>> m_Instances;
|
||||
QString userNameLookup(uid_t uid);
|
||||
static QString userNameLookup(uid_t uid);
|
||||
[[nodiscard]] LaunchTask unescapeExec(const QString &str, const QStringList &fields);
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <QStringView>
|
||||
#include <QVariant>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
|
||||
auto DesktopEntry::parserGroupHeader(const QString &str) noexcept
|
||||
{
|
||||
@ -23,6 +24,8 @@ auto DesktopEntry::parserGroupHeader(const QString &str) noexcept
|
||||
return it;
|
||||
}
|
||||
|
||||
void functest(QMap<QString, QString> p) {}
|
||||
|
||||
DesktopErrorCode DesktopEntry::parseEntry(const QString &str, decltype(m_entryMap)::iterator ¤tGroup) noexcept
|
||||
{
|
||||
if (str.startsWith("#")) {
|
||||
@ -87,6 +90,13 @@ DesktopErrorCode DesktopEntry::parseEntry(const QString &str, decltype(m_entryMa
|
||||
return DesktopErrorCode::NoError;
|
||||
}
|
||||
|
||||
std::optional<DesktopFile> DesktopFile::createTemporaryDesktopFile(QString content) noexcept
|
||||
{
|
||||
auto now = std::chrono::high_resolution_clock::now().time_since_epoch();
|
||||
auto nano = std::chrono::duration_cast<std::chrono::nanoseconds>(now);
|
||||
return DesktopFile{false, std::move(content), "", static_cast<size_t>(nano.count())};
|
||||
}
|
||||
|
||||
std::optional<DesktopFile> DesktopFile::searchDesktopFileByPath(const QString &desktopFile, DesktopErrorCode &err) noexcept
|
||||
{
|
||||
constexpr decltype(auto) desktopSuffix = ".desktop";
|
||||
@ -132,9 +142,9 @@ std::optional<DesktopFile> DesktopFile::searchDesktopFileByPath(const QString &d
|
||||
}
|
||||
|
||||
err = DesktopErrorCode::NoError;
|
||||
constexpr std::size_t nanoToSec = 1e9;
|
||||
constexpr std::size_t secToNano = 1e9;
|
||||
|
||||
return DesktopFile{std::move(path), std::move(id), buf.st_mtim.tv_sec * nanoToSec + buf.st_mtim.tv_nsec};
|
||||
return DesktopFile{true, std::move(path), std::move(id), buf.st_mtim.tv_sec * secToNano + buf.st_mtim.tv_nsec};
|
||||
}
|
||||
|
||||
std::optional<DesktopFile> DesktopFile::searchDesktopFileById(const QString &appId, DesktopErrorCode &err) noexcept
|
||||
@ -168,15 +178,20 @@ bool DesktopFile::modified(std::size_t time) const noexcept
|
||||
return time != m_mtime;
|
||||
}
|
||||
|
||||
DesktopErrorCode DesktopEntry::parse(const DesktopFile &appId) noexcept
|
||||
DesktopErrorCode DesktopEntry::parse(const DesktopFile &file) noexcept
|
||||
{
|
||||
auto file = QFile(appId.filePath());
|
||||
if (!file.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) {
|
||||
qWarning() << appId.filePath() << "can't open.";
|
||||
QTextStream in;
|
||||
if (file.persistence()) {
|
||||
auto sourceFile = QFile(file.fileSource());
|
||||
if (!sourceFile.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) {
|
||||
qWarning() << file.fileSource() << "can't open.";
|
||||
return DesktopErrorCode::OpenFailed;
|
||||
}
|
||||
in.setDevice(&sourceFile);
|
||||
} else {
|
||||
in.setString(const_cast<QString *>(&file.fileSource()));
|
||||
}
|
||||
|
||||
QTextStream in{&file};
|
||||
return parse(in);
|
||||
}
|
||||
|
||||
|
@ -30,33 +30,44 @@ struct DesktopFile
|
||||
DesktopFile &operator=(DesktopFile &&) = default;
|
||||
~DesktopFile() = default;
|
||||
|
||||
[[nodiscard]] const QString &filePath() const { return m_filePath; }
|
||||
[[nodiscard]] const QString &desktopId() const { return m_desktopId; }
|
||||
[[nodiscard]] const QString &fileSource() const noexcept { return m_fileSource; }
|
||||
[[nodiscard]] const QString &desktopId() const noexcept { return m_desktopId; }
|
||||
[[nodiscard]] bool persistence() const noexcept { return m_isPersistence; }
|
||||
[[nodiscard]] bool modified(std::size_t time) const noexcept;
|
||||
|
||||
static std::optional<DesktopFile> searchDesktopFileById(const QString &appId, DesktopErrorCode &err) noexcept;
|
||||
static std::optional<DesktopFile> searchDesktopFileByPath(const QString &desktopFilePath, DesktopErrorCode &err) noexcept;
|
||||
[[nodiscard]] bool modified(std::size_t time) const noexcept;
|
||||
static std::optional<DesktopFile> createTemporaryDesktopFile(QString content) noexcept;
|
||||
|
||||
private:
|
||||
DesktopFile(QString &&path, QString &&fileId, std::size_t mtime)
|
||||
: m_mtime(mtime)
|
||||
, m_filePath(std::move(path))
|
||||
DesktopFile(bool persistence, QString &&source, QString &&fileId, std::size_t mtime)
|
||||
: m_isPersistence(persistence)
|
||||
, m_mtime(mtime)
|
||||
, m_fileSource(std::move(source))
|
||||
, m_desktopId(std::move(fileId))
|
||||
{
|
||||
}
|
||||
|
||||
bool m_isPersistence;
|
||||
std::size_t m_mtime;
|
||||
QString m_filePath{""};
|
||||
QString m_fileSource{""};
|
||||
QString m_desktopId{""};
|
||||
};
|
||||
|
||||
class DesktopEntry
|
||||
{
|
||||
public:
|
||||
class Value : public QMap<QString, QString>
|
||||
class Value final : private QMap<QString, QString>
|
||||
{
|
||||
public:
|
||||
using QMap<QString, QString>::QMap;
|
||||
using QMap<QString, QString>::find;
|
||||
using QMap<QString, QString>::insert;
|
||||
using QMap<QString, QString>::cbegin;
|
||||
using QMap<QString, QString>::cend;
|
||||
using QMap<QString, QString>::begin;
|
||||
using QMap<QString, QString>::end;
|
||||
|
||||
QString toString(bool &ok) const noexcept;
|
||||
bool toBoolean(bool &ok) const noexcept;
|
||||
QString toIconString(bool &ok) const noexcept;
|
||||
|
@ -33,8 +33,8 @@ public:
|
||||
|
||||
m_am = new ApplicationManager1Service{std::make_unique<CGroupsIdentifier>(), bus.globalServerBus()};
|
||||
|
||||
DesktopFile file{"/usr/share/applications/test-Application.desktop", "test-Application", 0};
|
||||
QSharedPointer<ApplicationService> app = QSharedPointer<ApplicationService>::create(std::move(file));
|
||||
DesktopFile file{true, "/usr/share/applications/test-Application.desktop", "test-Application", 0};
|
||||
QSharedPointer<ApplicationService> app = QSharedPointer<ApplicationService>::create(std::move(file), nullptr);
|
||||
QSharedPointer<InstanceService> instance =
|
||||
QSharedPointer<InstanceService>::create(InstancePath.path().split('/').last(), ApplicationPath.path(), QString{"/"});
|
||||
app->m_Instances.insert(InstancePath, instance);
|
||||
|
@ -45,7 +45,7 @@ TEST_F(TestDesktopEntry, desktopFile)
|
||||
auto curDir = QDir::current();
|
||||
QString path{curDir.absolutePath() + QDir::separator() + "data" + QDir::separator() + "applications" + QDir::separator() +
|
||||
"deepin-editor.desktop"};
|
||||
EXPECT_EQ(exampleFile->filePath().toStdString(), path.toStdString());
|
||||
EXPECT_EQ(exampleFile->fileSource().toStdString(), path.toStdString());
|
||||
EXPECT_EQ(exampleFile->desktopId().toStdString(), "deepin-editor");
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ TEST_F(TestDesktopEntry, prase)
|
||||
const auto &exampleFile = file();
|
||||
ASSERT_FALSE(exampleFile.isNull());
|
||||
DesktopEntry entry;
|
||||
QFile in{exampleFile->filePath()};
|
||||
QFile in{exampleFile->fileSource()};
|
||||
ASSERT_TRUE(in.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text));
|
||||
QTextStream fs{&in};
|
||||
auto err = entry.parse(fs);
|
||||
|
Loading…
Reference in New Issue
Block a user