feat: add property "LastLaunchedTime"
1. reactor some utils implementation. 2. remove constexpr before `decltype(auto)` due to GCC bug. refer: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102229 Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
parent
2bdb9e99ee
commit
9f2a8b6798
@ -16,6 +16,7 @@
|
|||||||
</property>
|
</property>
|
||||||
|
|
||||||
<property name="AutoStart" type="b" access="readwrite"/>
|
<property name="AutoStart" type="b" access="readwrite"/>
|
||||||
|
<property name="LastLaunchedTime" type="t" access="read"/>
|
||||||
|
|
||||||
<property name="Instances" type="ao" access="read">
|
<property name="Instances" type="ao" access="read">
|
||||||
<annotation
|
<annotation
|
||||||
|
@ -25,7 +25,9 @@ void registerComplexDbusType()
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
#ifdef PROFILING_MODE
|
||||||
auto start = std::chrono::high_resolution_clock::now();
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
#endif
|
||||||
QCoreApplication app{argc, argv};
|
QCoreApplication app{argc, argv};
|
||||||
|
|
||||||
auto &bus = ApplicationManager1DBus::instance();
|
auto &bus = ApplicationManager1DBus::instance();
|
||||||
@ -36,24 +38,25 @@ int main(int argc, char *argv[])
|
|||||||
registerComplexDbusType();
|
registerComplexDbusType();
|
||||||
ApplicationManager1Service AMService{std::make_unique<CGroupsIdentifier>(), AMBus};
|
ApplicationManager1Service AMService{std::make_unique<CGroupsIdentifier>(), AMBus};
|
||||||
QList<DesktopFile> fileList{};
|
QList<DesktopFile> fileList{};
|
||||||
auto desktopFileDirs = getXDGDataDirs();
|
const auto &desktopFileDirs = getDesktopFileDirs();
|
||||||
|
|
||||||
applyIteratively(QList<QDir>(desktopFileDirs.begin(), desktopFileDirs.end()), [&AMService](const QFileInfo &info) -> bool {
|
applyIteratively(QList<QDir>(desktopFileDirs.cbegin(), desktopFileDirs.cend()), [&AMService](const QFileInfo &info) -> bool {
|
||||||
DesktopErrorCode err{DesktopErrorCode::NoError};
|
DesktopErrorCode err{DesktopErrorCode::NoError};
|
||||||
auto ret = DesktopFile::searchDesktopFileByPath(info.absoluteFilePath(), err);
|
auto ret = DesktopFile::searchDesktopFileByPath(info.absoluteFilePath(), err);
|
||||||
if (!ret.has_value()) {
|
if (!ret.has_value()) {
|
||||||
qWarning() << "failed to search File:" << err;
|
qWarning() << "failed to search File:" << err;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
AMService.addApplication(std::move(ret).value());
|
if (!AMService.addApplication(std::move(ret).value())) {
|
||||||
|
qWarning() << "add Application failed:" << ret->sourcePath() << "skip...";
|
||||||
|
}
|
||||||
return false; // means to apply this function to the rest of the files
|
return false; // means to apply this function to the rest of the files
|
||||||
});
|
});
|
||||||
|
#ifdef PROFILING_MODE
|
||||||
auto end = std::chrono::high_resolution_clock::now();
|
auto end = std::chrono::high_resolution_clock::now();
|
||||||
qCInfo(DDEAMProf) << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms";
|
qCInfo(DDEAMProf) << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms";
|
||||||
return
|
return 0;
|
||||||
#ifdef PROFILING_MODE
|
|
||||||
QCoreApplication::exec();
|
|
||||||
#else
|
#else
|
||||||
0;
|
return QCoreApplication::exec();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -52,12 +52,19 @@ QSharedPointer<ApplicationService> ApplicationService::createApplicationService(
|
|||||||
objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + QUuid::createUuid().toString(QUuid::Id128);
|
objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + QUuid::createUuid().toString(QUuid::Id128);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DesktopFileGuard guard{app->desktopFileSource()};
|
||||||
|
|
||||||
|
if (!guard.try_open()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
sourceStream.setDevice(app->desktopFileSource().sourceFile());
|
sourceStream.setDevice(app->desktopFileSource().sourceFile());
|
||||||
std::unique_ptr<DesktopEntry> entry{std::make_unique<DesktopEntry>()};
|
std::unique_ptr<DesktopEntry> entry{std::make_unique<DesktopEntry>()};
|
||||||
auto error = entry->parse(sourceStream);
|
auto error = entry->parse(sourceStream);
|
||||||
|
|
||||||
if (error != DesktopErrorCode::NoError) {
|
if (error != DesktopErrorCode::NoError) {
|
||||||
if (error != DesktopErrorCode::EntryKeyInvalid) {
|
if (error != DesktopErrorCode::EntryKeyInvalid) {
|
||||||
|
qWarning() << "parse failed:" << error;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,6 +72,7 @@ QSharedPointer<ApplicationService> ApplicationService::createApplicationService(
|
|||||||
if (auto val = entry->value(DesktopFileEntryKey, "Hidden"); val.has_value()) {
|
if (auto val = entry->value(DesktopFileEntryKey, "Hidden"); val.has_value()) {
|
||||||
bool ok{false};
|
bool ok{false};
|
||||||
if (auto hidden = val.value().toBoolean(ok); ok and hidden) {
|
if (auto hidden = val.value().toBoolean(ok); ok and hidden) {
|
||||||
|
qWarning() << "invalid hidden value:" << *val.value().find(defaultKeyStr);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -333,6 +341,11 @@ QString ApplicationService::id() const noexcept
|
|||||||
return m_desktopSource.desktopId();
|
return m_desktopSource.desktopId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qulonglong ApplicationService::lastLaunchedTime() const noexcept
|
||||||
|
{
|
||||||
|
return m_lastLaunch;
|
||||||
|
}
|
||||||
|
|
||||||
IconMap ApplicationService::icons() const
|
IconMap ApplicationService::icons() const
|
||||||
{
|
{
|
||||||
if (m_Icons) {
|
if (m_Icons) {
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
#include <QDBusContext>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -22,7 +23,7 @@
|
|||||||
#include "desktopicons.h"
|
#include "desktopicons.h"
|
||||||
#include "dbus/jobmanager1service.h"
|
#include "dbus/jobmanager1service.h"
|
||||||
|
|
||||||
class ApplicationService : public QObject
|
class ApplicationService : public QObject, public QDBusContext
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@ -38,6 +39,9 @@ public:
|
|||||||
Q_PROPERTY(QString ID READ id CONSTANT)
|
Q_PROPERTY(QString ID READ id CONSTANT)
|
||||||
[[nodiscard]] QString id() const noexcept;
|
[[nodiscard]] QString id() const noexcept;
|
||||||
|
|
||||||
|
Q_PROPERTY(qulonglong LastLaunchedTime READ lastLaunchedTime)
|
||||||
|
[[nodiscard]] qulonglong lastLaunchedTime() const noexcept;
|
||||||
|
|
||||||
Q_PROPERTY(IconMap Icons READ icons)
|
Q_PROPERTY(IconMap Icons READ icons)
|
||||||
[[nodiscard]] IconMap icons() const;
|
[[nodiscard]] IconMap icons() const;
|
||||||
IconMap &iconsRef();
|
IconMap &iconsRef();
|
||||||
@ -83,6 +87,7 @@ private:
|
|||||||
static QSharedPointer<ApplicationService> createApplicationService(DesktopFile source,
|
static QSharedPointer<ApplicationService> createApplicationService(DesktopFile source,
|
||||||
ApplicationManager1Service *parent) noexcept;
|
ApplicationManager1Service *parent) noexcept;
|
||||||
bool m_AutoStart{false};
|
bool m_AutoStart{false};
|
||||||
|
qlonglong m_lastLaunch{0};
|
||||||
QDBusObjectPath m_applicationPath;
|
QDBusObjectPath m_applicationPath;
|
||||||
QString m_launcher{getApplicationLauncherBinary()};
|
QString m_launcher{getApplicationLauncherBinary()};
|
||||||
DesktopFile m_desktopSource;
|
DesktopFile m_desktopSource;
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
auto DesktopEntry::parserGroupHeader(const QString &str) noexcept
|
auto DesktopEntry::parserGroupHeader(const QString &str) noexcept
|
||||||
{
|
{
|
||||||
@ -108,9 +109,33 @@ std::optional<DesktopFile> DesktopFile::createTemporaryDesktopFile(std::unique_p
|
|||||||
return DesktopFile{std::move(temporaryFile), "", mtime};
|
return DesktopFile{std::move(temporaryFile), "", mtime};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<DesktopFile> DesktopFile::createTemporaryDesktopFile(const QString &temporaryFile) noexcept
|
||||||
|
{
|
||||||
|
const static QString userTmp = QString{"/run/user/%1/"}.arg(getCurrentUID());
|
||||||
|
auto tempFile = std::make_unique<QFile>(QString{userTmp + QUuid::createUuid().toString(QUuid::Id128) + ".desktop"});
|
||||||
|
|
||||||
|
if (!tempFile->open(QFile::NewOnly | QFile::WriteOnly | QFile::Text)) {
|
||||||
|
qWarning() << "failed to create temporary desktop file:" << QFileInfo{*tempFile}.absoluteFilePath()
|
||||||
|
<< tempFile->errorString();
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto content = temporaryFile.toLocal8Bit();
|
||||||
|
auto writeByte = tempFile->write(content);
|
||||||
|
|
||||||
|
if (writeByte == -1 || writeByte != content.length()) {
|
||||||
|
qWarning() << "write to temporary file failed:" << tempFile->errorString();
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
tempFile->close();
|
||||||
|
|
||||||
|
return createTemporaryDesktopFile(std::move(tempFile));
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<DesktopFile> DesktopFile::searchDesktopFileByPath(const QString &desktopFile, DesktopErrorCode &err) noexcept
|
std::optional<DesktopFile> DesktopFile::searchDesktopFileByPath(const QString &desktopFile, DesktopErrorCode &err) noexcept
|
||||||
{
|
{
|
||||||
constexpr decltype(auto) desktopSuffix = ".desktop";
|
decltype(auto) desktopSuffix = ".desktop";
|
||||||
|
|
||||||
if (!desktopFile.endsWith(desktopSuffix)) {
|
if (!desktopFile.endsWith(desktopSuffix)) {
|
||||||
qWarning() << "file isn't a desktop file:" << desktopFile;
|
qWarning() << "file isn't a desktop file:" << desktopFile;
|
||||||
@ -128,7 +153,7 @@ std::optional<DesktopFile> DesktopFile::searchDesktopFileByPath(const QString &d
|
|||||||
QString path{desktopFile};
|
QString path{desktopFile};
|
||||||
QString id;
|
QString id;
|
||||||
|
|
||||||
const auto &XDGDataDirs = getXDGDataDirs();
|
const auto &XDGDataDirs = getDesktopFileDirs();
|
||||||
auto idGen = std::any_of(XDGDataDirs.cbegin(), XDGDataDirs.cend(), [&desktopFile](const QString &suffixPath) {
|
auto idGen = std::any_of(XDGDataDirs.cbegin(), XDGDataDirs.cend(), [&desktopFile](const QString &suffixPath) {
|
||||||
return desktopFile.startsWith(suffixPath);
|
return desktopFile.startsWith(suffixPath);
|
||||||
});
|
});
|
||||||
@ -160,7 +185,7 @@ std::optional<DesktopFile> DesktopFile::searchDesktopFileByPath(const QString &d
|
|||||||
|
|
||||||
std::optional<DesktopFile> DesktopFile::searchDesktopFileById(const QString &appId, DesktopErrorCode &err) noexcept
|
std::optional<DesktopFile> DesktopFile::searchDesktopFileById(const QString &appId, DesktopErrorCode &err) noexcept
|
||||||
{
|
{
|
||||||
auto XDGDataDirs = getXDGDataDirs();
|
auto XDGDataDirs = getDesktopFileDirs();
|
||||||
constexpr auto desktopSuffix = u8".desktop";
|
constexpr auto desktopSuffix = u8".desktop";
|
||||||
|
|
||||||
for (const auto &dir : XDGDataDirs) {
|
for (const auto &dir : XDGDataDirs) {
|
||||||
|
@ -45,6 +45,7 @@ struct DesktopFile
|
|||||||
|
|
||||||
static std::optional<DesktopFile> searchDesktopFileById(const QString &appId, DesktopErrorCode &err) noexcept;
|
static std::optional<DesktopFile> searchDesktopFileById(const QString &appId, DesktopErrorCode &err) noexcept;
|
||||||
static std::optional<DesktopFile> searchDesktopFileByPath(const QString &desktopFilePath, DesktopErrorCode &err) noexcept;
|
static std::optional<DesktopFile> searchDesktopFileByPath(const QString &desktopFilePath, DesktopErrorCode &err) noexcept;
|
||||||
|
static std::optional<DesktopFile> createTemporaryDesktopFile(const QString &temporaryFile) noexcept;
|
||||||
static std::optional<DesktopFile> createTemporaryDesktopFile(std::unique_ptr<QFile> temporaryFile) noexcept;
|
static std::optional<DesktopFile> createTemporaryDesktopFile(std::unique_ptr<QFile> temporaryFile) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -75,7 +76,20 @@ struct DesktopFileGuard
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool try_open() { return fileRef.m_fileSource->open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text); }
|
bool try_open()
|
||||||
|
{
|
||||||
|
if (fileRef.m_fileSource->isOpen()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ret = fileRef.m_fileSource->open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text);
|
||||||
|
if (!ret) {
|
||||||
|
qWarning() << "open desktop file failed:" << fileRef.m_fileSource->errorString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
~DesktopFileGuard()
|
~DesktopFileGuard()
|
||||||
{
|
{
|
||||||
if (fileRef.m_fileSource->isOpen()) {
|
if (fileRef.m_fileSource->isOpen()) {
|
||||||
@ -100,6 +114,7 @@ public:
|
|||||||
using QMap<QString, QString>::cend;
|
using QMap<QString, QString>::cend;
|
||||||
using QMap<QString, QString>::begin;
|
using QMap<QString, QString>::begin;
|
||||||
using QMap<QString, QString>::end;
|
using QMap<QString, QString>::end;
|
||||||
|
using QMap<QString, QString>::asKeyValueRange;
|
||||||
|
|
||||||
QString toString(bool &ok) const noexcept;
|
QString toString(bool &ok) const noexcept;
|
||||||
bool toBoolean(bool &ok) const noexcept;
|
bool toBoolean(bool &ok) const noexcept;
|
||||||
|
36
src/global.h
36
src/global.h
@ -48,7 +48,7 @@ template <typename T>
|
|||||||
using remove_cvr_t = std::remove_reference_t<std::remove_cv_t<T>>;
|
using remove_cvr_t = std::remove_reference_t<std::remove_cv_t<T>>;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void applyIteratively(QList<QDir> &&dirs, T &&func)
|
void applyIteratively(QList<QDir> dirs, T &&func)
|
||||||
{
|
{
|
||||||
static_assert(std::is_invocable_v<T, const QFileInfo &>, "apply function should only accept one QFileInfo");
|
static_assert(std::is_invocable_v<T, const QFileInfo &>, "apply function should only accept one QFileInfo");
|
||||||
static_assert(std::is_same_v<decltype(func(QFileInfo{})), bool>,
|
static_assert(std::is_same_v<decltype(func(QFileInfo{})), bool>,
|
||||||
@ -300,7 +300,7 @@ inline QString getRelativePathFromAppId(const QString &id)
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QStringList getXDGDataDirs()
|
inline QStringList getDesktopFileDirs()
|
||||||
{
|
{
|
||||||
const static auto XDGDataDirs = []() {
|
const static auto XDGDataDirs = []() {
|
||||||
auto XDGDataDirs = QString::fromLocal8Bit(qgetenv("XDG_DATA_DIRS")).split(':', Qt::SkipEmptyParts);
|
auto XDGDataDirs = QString::fromLocal8Bit(qgetenv("XDG_DATA_DIRS")).split(':', Qt::SkipEmptyParts);
|
||||||
@ -312,10 +312,10 @@ inline QStringList getXDGDataDirs()
|
|||||||
|
|
||||||
auto XDGDataHome = QString::fromLocal8Bit(qgetenv("XDG_DATA_HOME"));
|
auto XDGDataHome = QString::fromLocal8Bit(qgetenv("XDG_DATA_HOME"));
|
||||||
if (XDGDataHome.isEmpty()) {
|
if (XDGDataHome.isEmpty()) {
|
||||||
XDGDataHome = QString{qgetenv("HOME")} + QDir::separator() + ".local" + QDir::separator() + "share";
|
XDGDataHome = QString::fromLocal8Bit(qgetenv("HOME")) + QDir::separator() + ".local" + QDir::separator() + "share";
|
||||||
}
|
}
|
||||||
|
|
||||||
XDGDataDirs.push_front(XDGDataHome);
|
XDGDataDirs.push_front(std::move(XDGDataHome));
|
||||||
|
|
||||||
std::for_each(XDGDataDirs.begin(), XDGDataDirs.end(), [](QString &str) {
|
std::for_each(XDGDataDirs.begin(), XDGDataDirs.end(), [](QString &str) {
|
||||||
if (!str.endsWith(QDir::separator())) {
|
if (!str.endsWith(QDir::separator())) {
|
||||||
@ -330,6 +330,34 @@ inline QStringList getXDGDataDirs()
|
|||||||
return XDGDataDirs;
|
return XDGDataDirs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline QStringList getAutoStartDirs()
|
||||||
|
{
|
||||||
|
const static auto XDGConfigDirs = []() {
|
||||||
|
auto XDGConfigDirs = QString::fromLocal8Bit(qgetenv("XDG_CONFIG_DIRS")).split(':', Qt::SkipEmptyParts);
|
||||||
|
if (XDGConfigDirs.isEmpty()) {
|
||||||
|
XDGConfigDirs.append("/etc/xdg");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto XDGConfigHome = QString::fromLocal8Bit(qgetenv("XDG_CONFIG_HOME"));
|
||||||
|
if (XDGConfigHome.isEmpty()) {
|
||||||
|
XDGConfigHome = QString::fromLocal8Bit(qgetenv("HOME")) + QDir::separator() + ".config";
|
||||||
|
}
|
||||||
|
|
||||||
|
XDGConfigDirs.push_front(std::move(XDGConfigHome));
|
||||||
|
|
||||||
|
std::for_each(XDGConfigDirs.begin(), XDGConfigDirs.end(), [](QString &str) {
|
||||||
|
if (!str.endsWith(QDir::separator())) {
|
||||||
|
str.append(QDir::separator());
|
||||||
|
}
|
||||||
|
str.append("autostart");
|
||||||
|
});
|
||||||
|
|
||||||
|
return XDGConfigDirs;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return XDGConfigDirs;
|
||||||
|
}
|
||||||
|
|
||||||
inline QPair<QString, QString> processUnitName(const QString &unitName)
|
inline QPair<QString, QString> processUnitName(const QString &unitName)
|
||||||
{
|
{
|
||||||
QString instanceId;
|
QString instanceId;
|
||||||
|
@ -33,7 +33,7 @@ bool SystemdSignalDispatcher::connectToSignals() noexcept
|
|||||||
|
|
||||||
void SystemdSignalDispatcher::onUnitNew(QString unitName, QDBusObjectPath systemdUnitPath)
|
void SystemdSignalDispatcher::onUnitNew(QString unitName, QDBusObjectPath systemdUnitPath)
|
||||||
{
|
{
|
||||||
constexpr decltype(auto) appPrefix = u8"app-";
|
decltype(auto) appPrefix = u8"app-";
|
||||||
if (!unitName.startsWith(appPrefix)) {
|
if (!unitName.startsWith(appPrefix)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -43,7 +43,7 @@ void SystemdSignalDispatcher::onUnitNew(QString unitName, QDBusObjectPath system
|
|||||||
|
|
||||||
void SystemdSignalDispatcher::onUnitRemoved(QString unitName, QDBusObjectPath systemdUnitPath)
|
void SystemdSignalDispatcher::onUnitRemoved(QString unitName, QDBusObjectPath systemdUnitPath)
|
||||||
{
|
{
|
||||||
constexpr decltype(auto) appPrefix = u8"app-";
|
decltype(auto) appPrefix = u8"app-";
|
||||||
if (!unitName.startsWith(appPrefix)) {
|
if (!unitName.startsWith(appPrefix)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user