From c437b1726cdbce45891863460921ab0b8f368a88 Mon Sep 17 00:00:00 2001 From: zhaoyingzhen Date: Mon, 22 Jun 2026 17:40:21 +0800 Subject: [PATCH] fix: sync generated autostart desktop entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refresh generated autostart desktop files when application desktop entries are reloaded. - Avoid reusing stale in-memory autostart entries after the user deletes the generated file. - Rewrite AM-generated autostart entries from the current installed desktop entry. - Preserve the current Hidden value from disk so disabled autostart entries stay disabled. - Refuse to overwrite symlink autostart files and guard null desktop entries before syncing. 刷新生成的自启动 desktop 文件,使其跟随应用 desktop 更新。 - 用户删除生成文件后,避免继续复用内存中的旧自启动 entry。 - 对 AM 生成的自启动 entry,使用当前安装 desktop entry重新写入。 - 保留磁盘当前 Hidden 值,确保已禁用的自启动项不会被重新启用。 - 拒绝覆盖符号链接形式的自启动文件,并在同步前防御空 desktop entry。 Log: sync generated autostart desktop entries Pms: BUG-367265 Change-Id: I8a0e0733aa755d9481a0a2bf5f5ae0b72741d507 --- src/dbus/applicationmanager1service.cpp | 4 + src/dbus/applicationservice.cpp | 110 ++++++++++++++++++++---- src/dbus/applicationservice.h | 4 + 3 files changed, 102 insertions(+), 16 deletions(-) diff --git a/src/dbus/applicationmanager1service.cpp b/src/dbus/applicationmanager1service.cpp index b3978c77..9dc5c497 100644 --- a/src/dbus/applicationmanager1service.cpp +++ b/src/dbus/applicationmanager1service.cpp @@ -526,11 +526,13 @@ void ApplicationManager1Service::updateAutostartStatus() noexcept } app->setAutostartSource({sourcePath, std::move(parsedSource->entry)}); + app->syncGeneratedAutostartEntry(); return false; } if (auto existApp = m_applicationList.value(desktopId); existApp) { existApp->setAutostartSource({sourcePath, std::move(parsedSource->entry)}); + existApp->syncGeneratedAutostartEntry(); return false; } @@ -738,6 +740,8 @@ void ApplicationManager1Service::updateApplication(const QSharedPointerm_desktopSource != desktopFile && destApp->isAutoStart()) { destApp->m_desktopSource = std::move(desktopFile); } + + destApp->syncGeneratedAutostartEntry(); } void ApplicationManager1Service::ReloadApplications() diff --git a/src/dbus/applicationservice.cpp b/src/dbus/applicationservice.cpp index 4626f45e..e960a641 100644 --- a/src/dbus/applicationservice.cpp +++ b/src/dbus/applicationservice.cpp @@ -941,19 +941,104 @@ bool ApplicationService::autostartCheck() const noexcept bool ApplicationService::isAutoStart() const noexcept { - if (m_autostartSource.m_filePath.isEmpty()) { + if (!autostartSourceFileExists()) { return false; } return autostartCheck(); } +bool ApplicationService::autostartSourceFileExists() const noexcept +{ + return !m_autostartSource.m_filePath.isEmpty() && QFile::exists(m_autostartSource.m_filePath); +} + +bool ApplicationService::hasGeneratedAutostartSource() const noexcept +{ + auto group = m_autostartSource.m_entry.group(fromStaticRaw(DesktopFileEntryKey)); + if (!group.has_value()) { + return false; + } + + return group->get().contains(fromStaticRaw(DesktopEntryXDeepinGenerateSource)); +} + +bool ApplicationService::saveAutostartEntry(const QString &fileName, const DesktopEntry &entry) noexcept +{ + const QFileInfo autostartFileInfo{fileName}; + if (autostartFileInfo.isSymLink()) { + qWarning() << "refuse to overwrite symlink autostart file:" << fileName; + return false; + } + + QFile autostartFile{fileName}; + if (!autostartFile.open(QFile::WriteOnly | QFile::Text | QFile::Truncate)) { + qWarning() << "open file" << fileName << "failed:" << autostartFile.error(); + return false; + } + + auto content = toString(entry.data()).toLocal8Bit(); + auto writeBytes = autostartFile.write(content); + + if (writeBytes != content.size() || !autostartFile.flush()) { + qWarning() << "incomplete write:" << autostartFile.error(); + return false; + } + + return true; +} + +void ApplicationService::syncGeneratedAutostartEntry() noexcept +{ + if (!m_entry || !autostartSourceFileExists()) { + return; + } + + QFile autostartFile{m_autostartSource.m_filePath}; + if (!autostartFile.open(QFile::ReadOnly | QFile::Text)) { + qWarning() << "open file" << m_autostartSource.m_filePath << "failed:" << autostartFile.error(); + return; + } + + DesktopEntry currentEntry; + if (currentEntry.parse(autostartFile) != ParserError::NoError) { + qWarning() << "parse autostart file" << m_autostartSource.m_filePath << "failed"; + return; + } + + auto group = currentEntry.group(fromStaticRaw(DesktopFileEntryKey)); + if (!group.has_value() || !group->get().contains(fromStaticRaw(DesktopEntryXDeepinGenerateSource))) { + return; + } + + DesktopEntry newEntry = *m_entry; + newEntry.insert(fromStaticRaw(DesktopFileEntryKey), fromStaticRaw(DesktopEntryXDeepinGenerateSource), m_desktopSource.sourcePath()); + + auto hidden = currentEntry.value(fromStaticRaw(DesktopFileEntryKey), fromStaticRaw(DesktopEntryHidden)); + if (hidden) { + auto hiddenValue = hidden->get(); + newEntry.insert(fromStaticRaw(DesktopFileEntryKey), fromStaticRaw(DesktopEntryHidden), std::move(hiddenValue)); + } + + if (!saveAutostartEntry(m_autostartSource.m_filePath, newEntry)) { + return; + } + + setAutostartSource({m_autostartSource.m_filePath, newEntry}); +} + void ApplicationService::setAutoStart(bool autostart) noexcept { if (isAutoStart() == autostart) { return; } + if (!m_entry) { + qWarning() << "set autostart failed, desktop entry is null:" << id(); + safe_sendErrorReply(QDBusError::InternalError); + return; + } + const QDir startDir(getAutoStartDirs().constFirst()); if (!startDir.exists() && !startDir.mkpath(startDir.path())) { qWarning() << "mkpath " << startDir.path() << "failed"; @@ -962,16 +1047,11 @@ void ApplicationService::setAutoStart(bool autostart) noexcept } auto fileName = startDir.filePath(m_desktopSource.desktopId() % desktopSuffix); - QFile autostartFile{fileName}; - if (!autostartFile.open(QFile::WriteOnly | QFile::Text | QFile::Truncate)) { - qWarning() << "open file" << fileName << "failed:" << autostartFile.error(); - safe_sendErrorReply(QDBusError::Failed); - return; - } - DesktopEntry newEntry; QString originalSource; - if (!m_autostartSource.m_entry.data().isEmpty()) { + const bool shouldReuseAutostartEntry = autostartSourceFileExists() && !hasGeneratedAutostartSource() + && !m_autostartSource.m_entry.data().isEmpty(); + if (shouldReuseAutostartEntry) { newEntry = m_autostartSource.m_entry; auto source = newEntry.value(fromStaticRaw(DesktopFileEntryKey), fromStaticRaw(DesktopEntryXDeepinGenerateSource)); @@ -988,15 +1068,13 @@ void ApplicationService::setAutoStart(bool autostart) noexcept newEntry.insert(fromStaticRaw(DesktopFileEntryKey), fromStaticRaw(DesktopEntryXDeepinGenerateSource), originalSource); newEntry.insert(fromStaticRaw(DesktopFileEntryKey), fromStaticRaw(DesktopEntryHidden), !autostart); - setAutostartSource({fileName, newEntry}); - - auto hideAutostart = toString(newEntry.data()).toLocal8Bit(); - auto writeBytes = autostartFile.write(hideAutostart); - - if (writeBytes != hideAutostart.size() || !autostartFile.flush()) { - qWarning() << "incomplete write:" << autostartFile.error(); + if (!saveAutostartEntry(fileName, newEntry)) { + qWarning() << "set autostart failed:" << id() << "autostart:" << autostart << "file:" << fileName; + safe_sendErrorReply(QDBusError::Failed); + return; } + setAutostartSource({fileName, newEntry}); emit autostartChanged(); } diff --git a/src/dbus/applicationservice.h b/src/dbus/applicationservice.h index e8a0c2ff..7a544364 100644 --- a/src/dbus/applicationservice.h +++ b/src/dbus/applicationservice.h @@ -226,7 +226,11 @@ public Q_SLOTS: void updateAfterLaunch(bool isLaunch) noexcept; static bool shouldBeShown(const std::unique_ptr &entry) noexcept; [[nodiscard]] bool autostartCheck() const noexcept; + [[nodiscard]] bool autostartSourceFileExists() const noexcept; + [[nodiscard]] bool hasGeneratedAutostartSource() const noexcept; void setAutostartSource(AutostartSource &&source) noexcept; + bool saveAutostartEntry(const QString &fileName, const DesktopEntry &entry) noexcept; + void syncGeneratedAutostartEntry() noexcept; void appendExtraEnvironments(QVariantMap &runtimeOptions) const noexcept; void processCompatibility(const QString &action, QVariantMap &options, QString &execStr); [[nodiscard]] LaunchTask processExec(const QString &str, const QStringList& fields, const QString& workingDir) noexcept;