diff --git a/src/dbus/applicationmanager1service.cpp b/src/dbus/applicationmanager1service.cpp index 2e31369..c50cf1b 100644 --- a/src/dbus/applicationmanager1service.cpp +++ b/src/dbus/applicationmanager1service.cpp @@ -12,6 +12,7 @@ #include "desktopfilegenerator.h" #include "processguesser1service.h" #include +#include #include #include #include @@ -123,13 +124,13 @@ void ApplicationManager1Service::initService(QDBusConnection &connection) noexce auto *sigCon = new (std::nothrow) QMetaObject::Connection{}; - auto singleSlot = [watcher, sigCon, autostartList = std::move(needLaunch)]() { + auto singleSlot = [watcher, sigCon, autostartMap = std::move(needLaunch)]() { QObject::disconnect(*sigCon); delete sigCon; qDebug() << XSettings << "is registered."; - for (const auto &app : autostartList) { - app->Launch({}, {}, {}); + for (const auto &[app, realExec] : autostartMap.asKeyValueRange()) { + app->Launch({}, {}, {}, realExec); } watcher->deleteLater(); @@ -294,9 +295,9 @@ void ApplicationManager1Service::scanInstances() noexcept } } -QList> ApplicationManager1Service::scanAutoStart() noexcept +QHash, QString> ApplicationManager1Service::scanAutoStart() noexcept { - QList> ret; + QHash, QString> ret; auto autostartDirs = getAutoStartDirs(); std::map autostartItems; @@ -374,7 +375,9 @@ QList> ApplicationManager1Service::scanAutoSt } if (app) { - ret.append(app); + auto realExec = tmp.value(DesktopFileEntryKey, "Exec").value_or(QString{""}).toString(); + qInfo() << "launch normal autostart application " << app->id() << " by " << realExec; + ret.insert(app, realExec); continue; } @@ -388,8 +391,9 @@ QList> ApplicationManager1Service::scanAutoSt 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); + auto realExec = tmp.value(DesktopFileEntryKey, "Exec").value_or(QString{""}).toString(); + qInfo() << "launch exist autostart application " << (*appIt)->id() << " by " << realExec; + ret.insert(*appIt, realExec); continue; } @@ -401,7 +405,9 @@ QList> ApplicationManager1Service::scanAutoSt continue; } - ret.append(newApp); + auto realExec = newApp->m_entry->value(DesktopFileEntryKey, "Exec").value_or(QString{""}).toString(); + qInfo() << "launch new autostart application " << newApp->id() << " by " << realExec; + ret.insert(newApp, realExec); } return ret; @@ -642,7 +648,14 @@ QString ApplicationManager1Service::addUserApplication(const QVariantMap &deskto return {}; } - QDir xdgDataHome{getXDGDataHome() + "/applications"}; + QDir xdgDataHome; + QString dir{getXDGDataHome() + "/applications"}; + if (!xdgDataHome.mkpath(dir)) { + sendErrorReply(QDBusError::Failed, "couldn't create directory of user applications."); + return {}; + } + + xdgDataHome.setPath(dir); const auto &filePath = xdgDataHome.filePath(name); if (QFileInfo info{filePath}; info.exists() and info.isFile()) { diff --git a/src/dbus/applicationmanager1service.h b/src/dbus/applicationmanager1service.h index 6054381..df88cfa 100644 --- a/src/dbus/applicationmanager1service.h +++ b/src/dbus/applicationmanager1service.h @@ -74,7 +74,7 @@ private: void scanMimeInfos() noexcept; void scanApplications() noexcept; void scanInstances() noexcept; - QList> scanAutoStart() noexcept; + QHash, QString> 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 869dab9..eea56d0 100644 --- a/src/dbus/applicationservice.cpp +++ b/src/dbus/applicationservice.cpp @@ -173,9 +173,10 @@ bool ApplicationService::shouldBeShown(const std::unique_ptr &entr return true; } -QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringList &fields, const QVariantMap &options) +QDBusObjectPath +ApplicationService::Launch(const QString &action, const QStringList &fields, const QVariantMap &options, const QString &realExec) { - QString execStr; + QString execStr{}; bool ok; const auto &supportedActions = actions(); auto optionsMap = options; @@ -190,7 +191,16 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL optionsMap.insert("env", oldEnv); } - while (!action.isEmpty() and !supportedActions.isEmpty()) { // break trick + if (!realExec.isNull()) { // we want to replace exec of this applications. + if (realExec.isEmpty()) { + qWarning() << "try to replace exec but it's empty."; + return {}; + } + + execStr = realExec; + } + + while (execStr.isEmpty() and !action.isEmpty() and !supportedActions.isEmpty()) { // break trick if (auto index = supportedActions.indexOf(action); index == -1) { qWarning() << "can't find " << action << " in supported actions List. application will use default action to launch."; break; @@ -215,7 +225,9 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL if (!Actions) { QString msg{"application can't be executed."}; qWarning() << msg; - sendErrorReply(QDBusError::Failed, msg); + if (calledFromDBus()) { + sendErrorReply(QDBusError::Failed, msg); + } return {}; } @@ -223,7 +235,9 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL if (execStr.isEmpty()) { QString msg{"maybe entry actions's format is invalid, abort launch."}; qWarning() << msg; - sendErrorReply(QDBusError::Failed, msg); + if (calledFromDBus()) { + sendErrorReply(QDBusError::Failed, msg); + } return {}; } } @@ -235,14 +249,18 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL auto cmds = generateCommand(optionsMap); auto task = unescapeExec(execStr, fields); if (!task) { - sendErrorReply(QDBusError::InternalError, "Invalid Command."); + if (calledFromDBus()) { + sendErrorReply(QDBusError::InternalError, "Invalid Command."); + } return {}; } auto [bin, execCmds, res] = std::move(task); if (bin.isEmpty()) { qCritical() << "error command is detected, abort."; - sendErrorReply(QDBusError::Failed); + if (calledFromDBus()) { + sendErrorReply(QDBusError::Failed); + } return {}; } @@ -592,20 +610,30 @@ bool ApplicationService::autostartCheck(const QString &filePath) noexcept bool ApplicationService::isAutoStart() const noexcept { - auto autostartDirs = getAutoStartDirs(); - auto sourcePath = m_desktopSource.sourcePath(); - auto userAutostart = QDir{autostartDirs.first()}.filePath(id() + ".desktop"); + auto appId = id(); + auto dirs = getAutoStartDirs(); + QString destDesktopFile; - QFileInfo info{userAutostart}; - auto isOverride = info.exists() and info.isFile(); + applyIteratively( + QList(dirs.crbegin(), dirs.crend()), + [&appId, &destDesktopFile](const QFileInfo &file) { + auto filePath = file.absoluteFilePath(); + if (appId == getAutostartAppIdFromAbsolutePath(filePath)) { + destDesktopFile = filePath; + return true; + } + return false; + }, + QDir::Readable | QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot, + {"*.desktop"}, + QDir::Name | QDir::DirsLast); - 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); + if (destDesktopFile.isEmpty()) { + qDebug() << "couldn't find autostart desktopFile."; + return false; } - return isOverride and autostartCheck(userAutostart); + return autostartCheck(destDesktopFile); } void ApplicationService::setAutoStart(bool autostart) noexcept diff --git a/src/dbus/applicationservice.h b/src/dbus/applicationservice.h index f661849..b34094f 100644 --- a/src/dbus/applicationservice.h +++ b/src/dbus/applicationservice.h @@ -133,7 +133,9 @@ private Q_SLOTS: void onGlobalScaleFactorChanged() noexcept; public Q_SLOTS: - QDBusObjectPath Launch(const QString &action, const QStringList &fields, const QVariantMap &options); + // NOTE: 'realExec' only for internal implementation + QDBusObjectPath + Launch(const QString &action, const QStringList &fields, const QVariantMap &options, const QString &realExec = {}); [[nodiscard]] ObjectMap GetManagedObjects() const; [[nodiscard]] bool SendToDesktop() const noexcept; [[nodiscard]] bool RemoveFromDesktop() const noexcept; diff --git a/src/global.h b/src/global.h index 6f217e9..f560d4b 100644 --- a/src/global.h +++ b/src/global.h @@ -630,4 +630,18 @@ inline uint getPidFromPidFd(const QDBusUnixFileDescriptor &pidfd) noexcept return pid; } +inline QString getAutostartAppIdFromAbsolutePath(const QString &path) +{ + constexpr decltype(auto) desktopSuffix{u8".desktop"}; + auto tmp = path.chopped(sizeof(desktopSuffix) - 1); + auto components = tmp.split(QDir::separator(), Qt::SkipEmptyParts); + auto location = std::find(components.cbegin(), components.cend(), "autostart"); + if (location == components.cend()) { + return {}; + } + + auto appId = QStringList{location + 1, components.cend()}.join('-'); + return appId; +} + #endif