diff --git a/api/dbus/org.desktopspec.ApplicationManager1.Application.xml b/api/dbus/org.desktopspec.ApplicationManager1.Application.xml
index 57a09aa..af2b1e7 100644
--- a/api/dbus/org.desktopspec.ApplicationManager1.Application.xml
+++ b/api/dbus/org.desktopspec.ApplicationManager1.Application.xml
@@ -16,6 +16,7 @@
+
(), AMBus};
QList fileList{};
- auto desktopFileDirs = getXDGDataDirs();
+ const auto &desktopFileDirs = getDesktopFileDirs();
- applyIteratively(QList(desktopFileDirs.begin(), desktopFileDirs.end()), [&AMService](const QFileInfo &info) -> bool {
+ applyIteratively(QList(desktopFileDirs.cbegin(), desktopFileDirs.cend()), [&AMService](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;
}
- 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
});
+#ifdef PROFILING_MODE
auto end = std::chrono::high_resolution_clock::now();
qCInfo(DDEAMProf) << std::chrono::duration_cast(end - start).count() << "ms";
- return
-#ifdef PROFILING_MODE
- QCoreApplication::exec();
+ return 0;
#else
- 0;
+ return QCoreApplication::exec();
#endif
}
diff --git a/src/dbus/applicationservice.cpp b/src/dbus/applicationservice.cpp
index 66b9dc2..1ea2dfb 100644
--- a/src/dbus/applicationservice.cpp
+++ b/src/dbus/applicationservice.cpp
@@ -52,12 +52,19 @@ QSharedPointer ApplicationService::createApplicationService(
objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + QUuid::createUuid().toString(QUuid::Id128);
}
+ DesktopFileGuard guard{app->desktopFileSource()};
+
+ if (!guard.try_open()) {
+ return nullptr;
+ }
+
sourceStream.setDevice(app->desktopFileSource().sourceFile());
std::unique_ptr entry{std::make_unique()};
auto error = entry->parse(sourceStream);
if (error != DesktopErrorCode::NoError) {
if (error != DesktopErrorCode::EntryKeyInvalid) {
+ qWarning() << "parse failed:" << error;
return nullptr;
}
}
@@ -65,6 +72,7 @@ QSharedPointer ApplicationService::createApplicationService(
if (auto val = entry->value(DesktopFileEntryKey, "Hidden"); val.has_value()) {
bool ok{false};
if (auto hidden = val.value().toBoolean(ok); ok and hidden) {
+ qWarning() << "invalid hidden value:" << *val.value().find(defaultKeyStr);
return nullptr;
}
}
@@ -333,6 +341,11 @@ QString ApplicationService::id() const noexcept
return m_desktopSource.desktopId();
}
+qulonglong ApplicationService::lastLaunchedTime() const noexcept
+{
+ return m_lastLaunch;
+}
+
IconMap ApplicationService::icons() const
{
if (m_Icons) {
diff --git a/src/dbus/applicationservice.h b/src/dbus/applicationservice.h
index b6562de..f49352a 100644
--- a/src/dbus/applicationservice.h
+++ b/src/dbus/applicationservice.h
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -22,7 +23,7 @@
#include "desktopicons.h"
#include "dbus/jobmanager1service.h"
-class ApplicationService : public QObject
+class ApplicationService : public QObject, public QDBusContext
{
Q_OBJECT
public:
@@ -38,6 +39,9 @@ public:
Q_PROPERTY(QString ID READ id CONSTANT)
[[nodiscard]] QString id() const noexcept;
+ Q_PROPERTY(qulonglong LastLaunchedTime READ lastLaunchedTime)
+ [[nodiscard]] qulonglong lastLaunchedTime() const noexcept;
+
Q_PROPERTY(IconMap Icons READ icons)
[[nodiscard]] IconMap icons() const;
IconMap &iconsRef();
@@ -83,6 +87,7 @@ private:
static QSharedPointer createApplicationService(DesktopFile source,
ApplicationManager1Service *parent) noexcept;
bool m_AutoStart{false};
+ qlonglong m_lastLaunch{0};
QDBusObjectPath m_applicationPath;
QString m_launcher{getApplicationLauncherBinary()};
DesktopFile m_desktopSource;
diff --git a/src/desktopentry.cpp b/src/desktopentry.cpp
index 8c9c4a2..9a41816 100644
--- a/src/desktopentry.cpp
+++ b/src/desktopentry.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
auto DesktopEntry::parserGroupHeader(const QString &str) noexcept
{
@@ -108,9 +109,33 @@ std::optional DesktopFile::createTemporaryDesktopFile(std::unique_p
return DesktopFile{std::move(temporaryFile), "", mtime};
}
+std::optional DesktopFile::createTemporaryDesktopFile(const QString &temporaryFile) noexcept
+{
+ const static QString userTmp = QString{"/run/user/%1/"}.arg(getCurrentUID());
+ auto tempFile = std::make_unique(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::searchDesktopFileByPath(const QString &desktopFile, DesktopErrorCode &err) noexcept
{
- constexpr decltype(auto) desktopSuffix = ".desktop";
+ decltype(auto) desktopSuffix = ".desktop";
if (!desktopFile.endsWith(desktopSuffix)) {
qWarning() << "file isn't a desktop file:" << desktopFile;
@@ -128,7 +153,7 @@ std::optional DesktopFile::searchDesktopFileByPath(const QString &d
QString path{desktopFile};
QString id;
- const auto &XDGDataDirs = getXDGDataDirs();
+ const auto &XDGDataDirs = getDesktopFileDirs();
auto idGen = std::any_of(XDGDataDirs.cbegin(), XDGDataDirs.cend(), [&desktopFile](const QString &suffixPath) {
return desktopFile.startsWith(suffixPath);
});
@@ -160,7 +185,7 @@ std::optional DesktopFile::searchDesktopFileByPath(const QString &d
std::optional DesktopFile::searchDesktopFileById(const QString &appId, DesktopErrorCode &err) noexcept
{
- auto XDGDataDirs = getXDGDataDirs();
+ auto XDGDataDirs = getDesktopFileDirs();
constexpr auto desktopSuffix = u8".desktop";
for (const auto &dir : XDGDataDirs) {
diff --git a/src/desktopentry.h b/src/desktopentry.h
index b163498..b86f8e6 100644
--- a/src/desktopentry.h
+++ b/src/desktopentry.h
@@ -45,6 +45,7 @@ struct DesktopFile
static std::optional searchDesktopFileById(const QString &appId, DesktopErrorCode &err) noexcept;
static std::optional searchDesktopFileByPath(const QString &desktopFilePath, DesktopErrorCode &err) noexcept;
+ static std::optional createTemporaryDesktopFile(const QString &temporaryFile) noexcept;
static std::optional createTemporaryDesktopFile(std::unique_ptr temporaryFile) noexcept;
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()
{
if (fileRef.m_fileSource->isOpen()) {
@@ -100,6 +114,7 @@ public:
using QMap::cend;
using QMap::begin;
using QMap::end;
+ using QMap::asKeyValueRange;
QString toString(bool &ok) const noexcept;
bool toBoolean(bool &ok) const noexcept;
diff --git a/src/global.h b/src/global.h
index 12f7bdd..f118f9a 100644
--- a/src/global.h
+++ b/src/global.h
@@ -48,7 +48,7 @@ template
using remove_cvr_t = std::remove_reference_t>;
template
-void applyIteratively(QList &&dirs, T &&func)
+void applyIteratively(QList dirs, T &&func)
{
static_assert(std::is_invocable_v, "apply function should only accept one QFileInfo");
static_assert(std::is_same_v,
@@ -300,7 +300,7 @@ inline QString getRelativePathFromAppId(const QString &id)
return path;
}
-inline QStringList getXDGDataDirs()
+inline QStringList getDesktopFileDirs()
{
const static auto XDGDataDirs = []() {
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"));
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) {
if (!str.endsWith(QDir::separator())) {
@@ -330,6 +330,34 @@ inline QStringList getXDGDataDirs()
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 processUnitName(const QString &unitName)
{
QString instanceId;
diff --git a/src/systemdsignaldispatcher.cpp b/src/systemdsignaldispatcher.cpp
index db77e67..4c806cc 100644
--- a/src/systemdsignaldispatcher.cpp
+++ b/src/systemdsignaldispatcher.cpp
@@ -33,7 +33,7 @@ bool SystemdSignalDispatcher::connectToSignals() noexcept
void SystemdSignalDispatcher::onUnitNew(QString unitName, QDBusObjectPath systemdUnitPath)
{
- constexpr decltype(auto) appPrefix = u8"app-";
+ decltype(auto) appPrefix = u8"app-";
if (!unitName.startsWith(appPrefix)) {
return;
}
@@ -43,7 +43,7 @@ void SystemdSignalDispatcher::onUnitNew(QString unitName, QDBusObjectPath system
void SystemdSignalDispatcher::onUnitRemoved(QString unitName, QDBusObjectPath systemdUnitPath)
{
- constexpr decltype(auto) appPrefix = u8"app-";
+ decltype(auto) appPrefix = u8"app-";
if (!unitName.startsWith(appPrefix)) {
return;
}