diff --git a/src/applicationchecker.cpp b/src/applicationchecker.cpp index 21bab3b..7d20cc7 100644 --- a/src/applicationchecker.cpp +++ b/src/applicationchecker.cpp @@ -8,10 +8,10 @@ #include #include -bool ApplicationFilter::hiddenCheck(const std::unique_ptr &entry) noexcept +bool ApplicationFilter::hiddenCheck(const DesktopEntry &entry) noexcept { bool hidden{false}; - auto hiddenVal = entry->value(DesktopFileEntryKey, "Hidden"); + auto hiddenVal = entry.value(DesktopFileEntryKey, DesktopEntryHidden); if (hiddenVal.has_value()) { bool ok{false}; @@ -24,9 +24,9 @@ bool ApplicationFilter::hiddenCheck(const std::unique_ptr &entry) return hidden; } -bool ApplicationFilter::tryExecCheck(const std::unique_ptr &entry) noexcept +bool ApplicationFilter::tryExecCheck(const DesktopEntry &entry) noexcept { - auto tryExecVal = entry->value(DesktopFileEntryKey, "TryExec"); + auto tryExecVal = entry.value(DesktopFileEntryKey, "TryExec"); if (tryExecVal.has_value()) { auto executable = toString(tryExecVal.value()); if (executable.isEmpty()) { @@ -44,7 +44,7 @@ bool ApplicationFilter::tryExecCheck(const std::unique_ptr &entry) return false; } -bool ApplicationFilter::showInCheck(const std::unique_ptr &entry) noexcept +bool ApplicationFilter::showInCheck(const DesktopEntry &entry) noexcept { auto desktops = QString::fromLocal8Bit(qgetenv("XDG_CURRENT_DESKTOP")).split(':', Qt::SkipEmptyParts); if (desktops.isEmpty()) { @@ -53,7 +53,7 @@ bool ApplicationFilter::showInCheck(const std::unique_ptr &entry) desktops.removeDuplicates(); bool showInCurrentDE{true}; - auto onlyShowInVal = entry->value(DesktopFileEntryKey, "OnlyShowIn"); + auto onlyShowInVal = entry.value(DesktopFileEntryKey, "OnlyShowIn"); while (onlyShowInVal.has_value()) { auto deStr = toString(onlyShowInVal.value()); if (deStr.isEmpty()) { @@ -75,7 +75,7 @@ bool ApplicationFilter::showInCheck(const std::unique_ptr &entry) } bool notShowInCurrentDE{false}; - auto notShowInVal = entry->value(DesktopFileEntryKey, "NotShowIn"); + auto notShowInVal = entry.value(DesktopFileEntryKey, "NotShowIn"); while (notShowInVal.has_value()) { auto deStr = toString(notShowInVal.value()); if (deStr.isEmpty()) { @@ -98,3 +98,18 @@ bool ApplicationFilter::showInCheck(const std::unique_ptr &entry) return !showInCurrentDE or notShowInCurrentDE; } + +bool ApplicationFilter::hiddenCheck(const std::unique_ptr &entry) noexcept +{ + return hiddenCheck(*entry); +} + +bool ApplicationFilter::tryExecCheck(const std::unique_ptr &entry) noexcept +{ + return tryExecCheck(*entry); +} + +bool ApplicationFilter::showInCheck(const std::unique_ptr &entry) noexcept +{ + return showInCheck(*entry); +} diff --git a/src/applicationchecker.h b/src/applicationchecker.h index ef3350f..d5b57b6 100644 --- a/src/applicationchecker.h +++ b/src/applicationchecker.h @@ -13,6 +13,9 @@ namespace ApplicationFilter { bool hiddenCheck(const std::unique_ptr &entry) noexcept; bool tryExecCheck(const std::unique_ptr &entry) noexcept; bool showInCheck(const std::unique_ptr &entry) noexcept; +bool hiddenCheck(const DesktopEntry &entry) noexcept; +bool tryExecCheck(const DesktopEntry &entry) noexcept; +bool showInCheck(const DesktopEntry &entry) noexcept; } // namespace ApplicationFilter #endif diff --git a/src/constant.h b/src/constant.h index 8f65cc8..9021c42 100644 --- a/src/constant.h +++ b/src/constant.h @@ -23,6 +23,8 @@ constexpr auto DDEApplicationManager1MimeManager1ObjectPath = u8"/org/desktopspe constexpr auto DesktopFileEntryKey = u8"Desktop Entry"; constexpr auto DesktopFileActionKey = u8"Desktop Action "; constexpr auto DesktopFileDefaultKeyLocale = "default"; +constexpr auto X_Deepin_GenerateSource = u8"X-Deepin-GenerateSource"; +constexpr auto DesktopEntryHidden = u8"Hidden"; constexpr auto ApplicationManagerServerDBusName = #ifdef DDE_AM_USE_DEBUG_DBUS_NAME diff --git a/src/dbus/applicationmanager1service.cpp b/src/dbus/applicationmanager1service.cpp index cc79bf0..3cefc1b 100644 --- a/src/dbus/applicationmanager1service.cpp +++ b/src/dbus/applicationmanager1service.cpp @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later #include "applicationadaptor.h" +#include "applicationchecker.h" #include "dbus/applicationmanager1adaptor.h" #include "applicationservice.h" #include "dbus/AMobjectmanager1adaptor.h" @@ -79,6 +80,8 @@ void ApplicationManager1Service::initService(QDBusConnection &connection) noexce scanApplications(); + auto needLaunch = scanAutoStart(); + scanInstances(); loadHooks(); @@ -112,16 +115,20 @@ void ApplicationManager1Service::initService(QDBusConnection &connection) noexce constexpr auto XSettings = "org.deepin.dde.XSettings1"; - auto *watcher = - new QDBusServiceWatcher{XSettings, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForRegistration, this}; + auto *watcher = new (std::nothrow) + QDBusServiceWatcher{XSettings, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForRegistration, this}; - auto *sigCon = new QMetaObject::Connection{}; + auto *sigCon = new (std::nothrow) QMetaObject::Connection{}; - auto singleSlot = [this, watcher, sigCon]() { + auto singleSlot = [watcher, sigCon, autostartList = std::move(needLaunch)]() { QObject::disconnect(*sigCon); delete sigCon; qDebug() << XSettings << "is registered."; - scanAutoStart(); + + for (const auto &app : autostartList) { + app->Launch({}, {}, {}); + } + watcher->deleteLater(); }; @@ -236,23 +243,29 @@ void ApplicationManager1Service::scanApplications() noexcept { const auto &desktopFileDirs = getDesktopFileDirs(); + std::map fileMap; applyIteratively( QList(desktopFileDirs.crbegin(), desktopFileDirs.crend()), - [this](const QFileInfo &info) -> bool { + [&fileMap](const QFileInfo &info) -> bool { ParserError err{ParserError::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..."; - } + auto file = std::move(ret).value(); + fileMap.insert_or_assign(file.desktopId(), std::move(file)); 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); + + for (auto &&[k, v] : std::move(fileMap)) { + if (!addApplication(std::move(v))) { + qWarning() << "add Application" << k << " failed, skip..."; + } + } } void ApplicationManager1Service::scanInstances() noexcept @@ -278,32 +291,117 @@ void ApplicationManager1Service::scanInstances() noexcept } } -void ApplicationManager1Service::scanAutoStart() noexcept +QList> ApplicationManager1Service::scanAutoStart() noexcept { + QList> ret; auto autostartDirs = getAutoStartDirs(); - QStringList needToLaunch; + std::map autostartItems; + applyIteratively( - QList{autostartDirs.cbegin(), autostartDirs.cend()}, - [&needToLaunch](const QFileInfo &info) { - if (info.isSymbolicLink()) { - needToLaunch.emplace_back(info.symLinkTarget()); + QList{autostartDirs.crbegin(), autostartDirs.crend()}, + [&autostartItems](const QFileInfo &info) { + ParserError err{ParserError::InternalError}; + auto desktopSource = DesktopFile::searchDesktopFileByPath(info.absoluteFilePath(), err); + if (err != ParserError::NoError) { + qWarning() << "skip" << info.absoluteFilePath(); + return false; } + auto file = std::move(desktopSource).value(); + autostartItems.insert_or_assign(file.desktopId(), std::move(file)); return false; }, - QDir::Readable | QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot, + QDir::Readable | QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot, {"*.desktop"}, QDir::Name | QDir::DirsLast); - while (!needToLaunch.isEmpty()) { - const auto &filePath = needToLaunch.takeFirst(); - auto appIt = - std::find_if(m_applicationList.constKeyValueBegin(), - m_applicationList.constKeyValueEnd(), - [&filePath](const auto &pair) { return pair.second->m_desktopSource.sourcePath() == filePath; }); - if (appIt != m_applicationList.constKeyValueEnd()) { - appIt->second->Launch({}, {}, {}); + for (auto &it : autostartItems) { + auto desktopFile = std::move(it.second); + + DesktopFileGuard guard{desktopFile}; + if (!guard.try_open()) { + continue; } + + auto &file = desktopFile.sourceFileRef(); + QTextStream stream{&file}; + DesktopEntry tmp; + auto err = tmp.parse(stream); + if (err != ParserError::NoError) { + qWarning() << "parse autostart file" << desktopFile.sourcePath() << " error:" << err; + continue; + } + + QSharedPointer app{nullptr}; + auto asApplication = tmp.value(DesktopFileEntryKey, X_Deepin_GenerateSource).value_or(DesktopEntry::Value{}); + if (!asApplication.isNull()) { // modified by application manager + auto appSource = asApplication.toString(); + + QFileInfo sourceInfo{appSource}; + if ((!sourceInfo.exists() or !sourceInfo.isFile()) and !file.remove()) { + qWarning() << "remove invalid autostart file error:" << file.error(); + continue; + } + + // add original application + auto desktopSource = DesktopFile::searchDesktopFileByPath(appSource, err); + if (err != ParserError::NoError) { + qWarning() << "search autostart application failed:" << err; + continue; + } + auto source = std::move(desktopSource).value(); + + if (source.desktopId().isEmpty()) { + qWarning() << X_Deepin_GenerateSource << "is" << appSource + << ", but couldn't find it in applications, maybe this autostart file has been modified, skip."; + continue; + } + + // add application directly, it wouldn't add the same application twice. + app = addApplication(std::move(source)); + if (!app) { + qWarning() << "add autostart application failed, skip."; + continue; + } + } + + auto shouldLaunch = tmp.value(DesktopFileEntryKey, DesktopEntryHidden).value_or(DesktopEntry::Value{}); + if (!shouldLaunch.isNull() and (shouldLaunch.toString().compare("true", Qt::CaseInsensitive) == 0)) { + qInfo() << "shouldn't launch this autoStart item."; + continue; + } + + if (app) { + ret.append(app); + continue; + } + + // maybe some application generate autostart desktop by itself + if (ApplicationFilter::tryExecCheck(tmp) or ApplicationFilter::showInCheck(tmp)) { + qInfo() << "autostart application couldn't pass check."; + continue; + } + + if (auto appIt = std::find_if(m_applicationList.cbegin(), + m_applicationList.cend(), + [&desktopFile](const auto &app) { return desktopFile.desktopId() == app->id(); }); + appIt != m_applicationList.cend()) { + qInfo() << "app already exists. use it to launch instance."; + ret.append(*appIt); + continue; + } + + guard.close(); + // new application + auto newApp = addApplication(std::move(desktopFile)); + if (!newApp) { + qWarning() << "add autostart application failed, skip."; + continue; + } + + ret.append(newApp); } + + return ret; } void ApplicationManager1Service::loadHooks() noexcept @@ -337,36 +435,39 @@ QList ApplicationManager1Service::list() const return m_applicationList.keys(); } -bool ApplicationManager1Service::addApplication(DesktopFile desktopFileSource) noexcept +QSharedPointer ApplicationManager1Service::addApplication(DesktopFile desktopFileSource) noexcept { + auto source = desktopFileSource.sourcePath(); QSharedPointer application = ApplicationService::createApplicationService(std::move(desktopFileSource), this, m_storage); if (!application) { - return false; + qWarning() << "can't create application" << source; + return nullptr; } - if (m_applicationList.constFind(application->applicationPath()) != m_applicationList.cend()) { + if (auto app = m_applicationList.constFind(application->applicationPath()); app != m_applicationList.cend()) { qInfo() << "this application already exists." - << "desktop source:" << application->desktopFileSource().sourcePath(); - return false; + << "current desktop source:" << application->desktopFileSource().sourcePath() + << "exists app source:" << app->data()->desktopFileSource().sourcePath(); + return *app; } auto *ptr = application.data(); if (auto *adaptor = new (std::nothrow) ApplicationAdaptor{ptr}; adaptor == nullptr) { qCritical() << "new ApplicationAdaptor failed."; - return false; + return nullptr; } if (!registerObjectToDBus(ptr, application->applicationPath().path(), ApplicationInterface)) { - return false; + return nullptr; } m_applicationList.insert(application->applicationPath(), application); emit listChanged(); emit InterfacesAdded(application->applicationPath(), getChildInterfacesAndPropertiesFromObject(ptr)); - return true; + return application; } void ApplicationManager1Service::removeOneApplication(const QDBusObjectPath &application) noexcept diff --git a/src/dbus/applicationmanager1service.h b/src/dbus/applicationmanager1service.h index a480f3a..6054381 100644 --- a/src/dbus/applicationmanager1service.h +++ b/src/dbus/applicationmanager1service.h @@ -36,7 +36,7 @@ public: [[nodiscard]] QList list() const; void initService(QDBusConnection &connection) noexcept; - bool addApplication(DesktopFile desktopFileSource) noexcept; + QSharedPointer addApplication(DesktopFile desktopFileSource) noexcept; void removeOneApplication(const QDBusObjectPath &application) noexcept; void removeAllApplication() noexcept; [[nodiscard]] QMap> @@ -74,7 +74,7 @@ private: void scanMimeInfos() noexcept; void scanApplications() noexcept; void scanInstances() noexcept; - void scanAutoStart() noexcept; + QList> scanAutoStart() noexcept; void loadHooks() noexcept; void addInstanceToApplication(const QString &unitName, const QDBusObjectPath &systemdUnitPath); void removeInstanceFromApplication(const QString &unitName, const QDBusObjectPath &systemdUnitPath); diff --git a/src/dbus/applicationservice.cpp b/src/dbus/applicationservice.cpp index 80c06cc..ee60a6c 100644 --- a/src/dbus/applicationservice.cpp +++ b/src/dbus/applicationservice.cpp @@ -6,10 +6,14 @@ #include "APPobjectmanager1adaptor.h" #include "applicationchecker.h" #include "applicationmanagerstorage.h" +#include "constant.h" +#include "global.h" +#include "iniParser.h" #include "propertiesForwarder.h" #include "dbus/instanceadaptor.h" #include "launchoptions.h" #include "desktopentry.h" +#include "desktopfileparser.h" #include #include #include @@ -19,6 +23,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -102,6 +111,7 @@ QSharedPointer ApplicationService::createApplicationService( DesktopFileGuard guard{app->desktopFileSource()}; if (!guard.try_open()) { + qDebug() << "open source desktop failed."; return nullptr; } @@ -139,14 +149,17 @@ QSharedPointer ApplicationService::createApplicationService( bool ApplicationService::shouldBeShown(const std::unique_ptr &entry) noexcept { if (ApplicationFilter::hiddenCheck(entry)) { + qDebug() << "hidden check failed."; return false; } if (ApplicationFilter::tryExecCheck(entry)) { + qDebug() << "tryExec check failed"; return false; } if (ApplicationFilter::showInCheck(entry)) { + qDebug() << "showIn check failed."; return false; } @@ -541,46 +554,76 @@ void ApplicationService::setScaleFactor(double value) noexcept emit scaleFactorChanged(); } -bool ApplicationService::autostartCheck(const QString &linkPath) const noexcept +bool ApplicationService::autostartCheck(const QString &filePath) noexcept { - QFileInfo info{linkPath}; + qDebug() << "current check autostart file:" << filePath; - if (info.exists()) { - if (info.isSymbolicLink() and info.symLinkTarget() == m_desktopSource.sourcePath()) { - return true; - } - qWarning() << "same name desktop file exists:" << linkPath << "but this may not created by AM."; + QFile file{filePath}; + if (!file.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) { + qWarning() << "open" << filePath << "failed:" << file.errorString(); + return false; } - return false; + QTextStream stream{&file}; + DesktopEntry s; + if (auto err = s.parse(stream); err != ParserError::NoError) { + qWarning() << "parse" << filePath << "failed:" << err; + return false; + } + + auto hiddenVal = s.value(DesktopFileEntryKey, DesktopEntryHidden); + if (!hiddenVal) { + qDebug() << "no hidden in autostart desktop"; + return true; + } + + auto hidden = hiddenVal.value().toString(); + return hidden.compare("false", Qt::CaseInsensitive) == 0; } bool ApplicationService::isAutoStart() const noexcept { - auto path = getAutoStartDirs().first(); - auto linkName = QDir{path}.filePath(m_desktopSource.desktopId() + ".desktop"); - return autostartCheck(linkName); + auto autostartDirs = getAutoStartDirs(); + auto sourcePath = m_desktopSource.sourcePath(); + auto userAutostart = QDir{autostartDirs.first()}.filePath(id() + ".desktop"); + + QFileInfo info{userAutostart}; + auto isOverride = info.exists() and info.isFile(); + + if (std::any_of(autostartDirs.cbegin(), autostartDirs.cend(), [&sourcePath](const QString &dir) { + return sourcePath.startsWith(dir); + })) { // load from autostart + return isOverride ? autostartCheck(userAutostart) : autostartCheck(sourcePath); + } + + return isOverride and autostartCheck(userAutostart); } void ApplicationService::setAutoStart(bool autostart) noexcept { - auto path = getAutoStartDirs().first(); - auto linkName = QDir{path}.filePath(m_desktopSource.desktopId() + ".desktop"); - auto &file = m_desktopSource.sourceFileRef(); + if (isAutoStart() == autostart) { + return; + } - if (autostart) { - if (!autostartCheck(linkName) and !file.link(linkName)) { - qWarning() << "link to autostart failed:" << file.errorString(); - return; - } - } else { - if (autostartCheck(linkName)) { - QFile linkFile{linkName}; - if (!linkFile.remove()) { - qWarning() << "remove link failed:" << linkFile.errorString(); - return; - } - } + auto fileName = QDir{getAutoStartDirs().first()}.filePath(m_desktopSource.desktopId() + ".desktop"); + QFile autostartFile{fileName}; + if (!autostartFile.open(QFile::WriteOnly | QFile::Text | QFile::Truncate)) { + qWarning() << "open file" << fileName << "failed:" << autostartFile.error(); + sendErrorReply(QDBusError::Failed); + return; + } + + auto newEntry = *m_entry; + newEntry.insert(DesktopFileEntryKey, X_Deepin_GenerateSource, m_desktopSource.sourcePath()); + newEntry.insert(DesktopFileEntryKey, DesktopEntryHidden, !autostart); + + auto hideAutostart = toString(newEntry.data()).toLocal8Bit(); + auto writeBytes = autostartFile.write(hideAutostart); + + if (writeBytes != hideAutostart.size() or !autostartFile.flush()) { + qWarning() << "incomplete write:" << autostartFile.error(); + sendErrorReply(QDBusError::Failed, "set failed: filesystem error."); + return; } emit autostartChanged(); @@ -1021,7 +1064,7 @@ double getScaleFactor() noexcept QString getDeepinWineScaleFactor(const QString &appId) noexcept { qCritical() << "Don't using env to control the window scale factor, this function" - "should via using graphisc server(Wayland Compositor/Xorg Xft) in deepin wine."; + "should via using graphic server(Wayland Compositor/Xorg Xft) in deepin wine."; QString factor{"1.0"}; auto objectPath = QString{"/dde_launcher/org_deepin_dde_launcher/%1"}.arg(getCurrentUID()); diff --git a/src/dbus/applicationservice.h b/src/dbus/applicationservice.h index cec78ad..f661849 100644 --- a/src/dbus/applicationservice.h +++ b/src/dbus/applicationservice.h @@ -177,7 +177,7 @@ private: QMap> m_Instances; void updateAfterLaunch(bool isLaunch) noexcept; static bool shouldBeShown(const std::unique_ptr &entry) noexcept; - [[nodiscard]] bool autostartCheck(const QString &linkPath) const noexcept; + [[nodiscard]] static bool autostartCheck(const QString &filePath) noexcept; [[nodiscard]] ApplicationManager1Service *parent() { return dynamic_cast(QObject::parent()); } [[nodiscard]] const ApplicationManager1Service *parent() const { diff --git a/src/desktopentry.cpp b/src/desktopentry.cpp index 95a6042..00be80a 100644 --- a/src/desktopentry.cpp +++ b/src/desktopentry.cpp @@ -111,18 +111,31 @@ std::optional DesktopFile::searchDesktopFileByPath(const QString &d return std::nullopt; } - QString path{desktopFile}; - QString id; - const auto &XDGDataDirs = getDesktopFileDirs(); - auto idGen = std::any_of(XDGDataDirs.cbegin(), XDGDataDirs.cend(), [&desktopFile](const QString &suffixPath) { + const auto &autostartDirs = getAutoStartDirs(); + auto IsCommonApp = std::any_of(XDGDataDirs.cbegin(), XDGDataDirs.cend(), [&desktopFile](const QString &suffixPath) { return desktopFile.startsWith(suffixPath); }); - if (idGen) { + auto IsAutostartApp = std::any_of(autostartDirs.cbegin(), autostartDirs.cend(), [&desktopFile](const QString &suffixPath) { + return desktopFile.startsWith(suffixPath); + }); + + QString path{desktopFile}; + QString id; + + if (IsCommonApp or IsAutostartApp) { auto tmp = path.chopped(sizeof(desktopSuffix) - 1); - auto components = tmp.split(QDir::separator()).toList(); - auto it = std::find(components.cbegin(), components.cend(), "applications"); + auto components = tmp.split(QDir::separator(), Qt::SkipEmptyParts).toList(); + decltype(components)::const_iterator it; + if (auto appIt = std::find(components.cbegin(), components.cend(), "applications"); appIt != components.cend()) { + it = appIt; + + } else if (auto autostartIt = std::find(components.cbegin(), components.cend(), "autostart"); + autostartIt != components.cend()) { + it = autostartIt; + } + QString FileId; ++it; while (it != components.cend()) { @@ -236,6 +249,16 @@ std::optional DesktopEntry::value(const QString &groupKey, return *it; } +void DesktopEntry::insert(const QString &key, const QString &valueKey, Value &&val) noexcept +{ + auto outer = m_entryMap.find(key); + if (outer == m_entryMap.end()) { + outer = m_entryMap.insert(key, {}); + } + + outer->insert(valueKey, val); +} + QString unescape(const QString &str, bool shellMode) noexcept { QString unescapedStr; diff --git a/src/desktopentry.h b/src/desktopentry.h index e17b731..10e4c89 100644 --- a/src/desktopentry.h +++ b/src/desktopentry.h @@ -78,6 +78,10 @@ struct DesktopFileGuard bool try_open() { + if (!fileRef.m_fileSource) { + return false; + } + if (fileRef.m_fileSource->isOpen()) { return true; } @@ -90,13 +94,19 @@ struct DesktopFileGuard return ret; } - ~DesktopFileGuard() + void close() { + if (!fileRef.m_fileSource) { + return; + } + if (fileRef.m_fileSource->isOpen()) { fileRef.m_fileSource->close(); } } + ~DesktopFileGuard() { close(); } + private: const DesktopFile &fileRef; }; @@ -116,6 +126,8 @@ public: [[nodiscard]] ParserError parse(QTextStream &stream) noexcept; [[nodiscard]] std::optional> group(const QString &key) const noexcept; [[nodiscard]] std::optional value(const QString &key, const QString &valueKey) const noexcept; + void insert(const QString &key, const QString &valueKey, Value &&val) noexcept; + [[nodiscard]] const auto &data() const noexcept { return m_entryMap; } friend bool operator==(const DesktopEntry &lhs, const DesktopEntry &rhs); friend bool operator!=(const DesktopEntry &lhs, const DesktopEntry &rhs); diff --git a/src/global.h b/src/global.h index 395bf39..18d9285 100644 --- a/src/global.h +++ b/src/global.h @@ -403,7 +403,12 @@ inline QStringList getXDGDataDirs() XDGDataDirs.append("/usr/share"); } - XDGDataDirs.push_front(getXDGDataHome()); + auto XDGDataHome = getXDGDataHome(); + if (XDGDataDirs.contains(XDGDataHome)) { + XDGDataDirs.removeAll(XDGDataHome); + } + + XDGDataDirs.push_front(XDGDataHome); return XDGDataDirs; } @@ -416,6 +421,7 @@ inline QStringList getDesktopFileDirs() } str.append("applications"); }); + return XDGDataDirs; }