Skip to content

Commit a40a096

Browse files
committed
refactor: optimize performance, adopt Qt 6 APIs, and fix XDG compliance
- Use QHash instead of QMap for O(1) lookup performance - Adopt QStringView to eliminate unnecessary string copies - Use QSaveFile for atomic writes with batch update support - Modernize with structured bindings, qTokenize, and Qt 6 string literals - Fix XDG spec compliance: proper directory validation and file existence checks - Centralize string constants to prevent typos and ease maintenance Signed-off-by: ComixHe <heyuming@deepin.org>
1 parent e2373f2 commit a40a096

35 files changed

Lines changed: 2101 additions & 1048 deletions

apps/dde-am/src/launcher.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,12 @@ DExpected<void> Launcher::launch() noexcept
121121
// Build options map
122122
QVariantMap options;
123123
if (!m_environmentVariables.isEmpty()) {
124-
options.insert(u"env"_s, m_environmentVariables);
124+
options.insert(fromStaticRaw(EnvOption), m_environmentVariables);
125125
}
126126

127127
// Mark autostart launches so AM can suppress splash
128128
if (m_autostart) {
129-
options.insert(u"_autostart"_s, true);
129+
options.insert(fromStaticRaw(BuiltInAutostartOption), true);
130130
}
131131

132132
auto msg = QDBusMessage::createMethodCall(

apps/dde-application-manager/src/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "dbus/applicationmanager1service.h"
88
#include "global.h"
99
#include <QDBusConnection>
10+
#include <QCoreApplication>
1011
#include <QGuiApplication>
1112

1213
Q_LOGGING_CATEGORY(DDEAMProf, "dde.am.prof", QtInfoMsg)

apps/dde-autostart/src/main.cpp

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
#include "desktopentry.h"
88

99
#include <QCoreApplication>
10+
#include <QDir>
1011
#include <QDBusServiceWatcher>
1112
#include <QProcess>
13+
#include <QSet>
1214

1315
using namespace Qt::StringLiterals;
1416

@@ -39,47 +41,50 @@ void launchApplication(const DesktopFile &file)
3941

4042
void scanAndLaunch()
4143
{
42-
auto autostartDirs = getAutoStartDirs();
43-
std::unordered_map<QString, DesktopFile> autostartItems;
44-
45-
applyIteratively(
46-
QList<QDir>{autostartDirs.crbegin(), autostartDirs.crend()},
47-
[&autostartItems](const QFileInfo &info) {
48-
ParserError err{ParserError::InternalError};
49-
auto desktopSource = DesktopFile::searchDesktopFileByPath(info.absoluteFilePath(), err);
50-
if (err != ParserError::NoError) {
51-
qWarning() << "skip" << info.absoluteFilePath();
52-
return false;
53-
}
54-
auto file = std::move(desktopSource).value();
55-
autostartItems.insert_or_assign(file.desktopId(), std::move(file));
56-
return false;
57-
},
58-
QDir::Readable | QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot,
59-
{"*.desktop"},
60-
QDir::Name | QDir::DirsLast);
61-
62-
for (const auto &[id, desktopFile] : autostartItems) {
63-
DesktopFileGuard guard{desktopFile};
64-
if (!guard.try_open()) {
44+
QSet<QString> seenFileNames;
45+
for (const auto &dirPath : getAutoStartDirs()) {
46+
const QDir dir{dirPath};
47+
if (!dir.exists()) {
6548
continue;
6649
}
6750

68-
auto &file = desktopFile.sourceFileRef();
69-
QTextStream stream{&file};
70-
DesktopEntry tmp;
71-
auto err = tmp.parse(stream);
72-
if (err != ParserError::NoError) {
73-
qWarning() << "parse autostart file" << desktopFile.sourcePath() << " error:" << err;
74-
continue;
75-
}
51+
const auto infoList = dir.entryInfoList({u"*.desktop"_s}, QDir::Files | QDir::NoDotAndDotDot | QDir::Readable, QDir::Name);
52+
for (const auto &info : infoList) {
53+
if (seenFileNames.contains(info.fileName())) {
54+
continue;
55+
}
7656

77-
if (ApplicationFilter::tryExecCheck(tmp) || ApplicationFilter::showInCheck(tmp) || ApplicationFilter::hiddenCheck(tmp)) {
78-
qInfo() << "autostart application " << id << " couldn't pass check:" << desktopFile.sourcePath();
79-
continue;
80-
}
57+
ParserError searchErr{ParserError::InternalError};
58+
auto desktopSource = DesktopFile::searchDesktopFileByPath(info.absoluteFilePath(), searchErr);
59+
if (searchErr != ParserError::NoError) {
60+
qWarning() << "skip" << info.absoluteFilePath();
61+
continue;
62+
}
63+
64+
auto desktopFile = std::move(desktopSource).value();
65+
seenFileNames.insert(info.fileName());
66+
const auto &id = desktopFile.desktopId();
67+
DesktopFileGuard guard{desktopFile};
68+
if (!guard.try_open()) {
69+
continue;
70+
}
71+
72+
auto &file = desktopFile.sourceFileRef();
73+
DesktopEntry tmp;
74+
auto parseErr = tmp.parse(file);
75+
if (parseErr != ParserError::NoError) {
76+
qWarning() << "parse autostart file" << desktopFile.sourcePath() << " error:" << parseErr;
77+
continue;
78+
}
79+
80+
if (ApplicationFilter::tryExecCheck(tmp) || ApplicationFilter::showInCheck(tmp)
81+
|| ApplicationFilter::hiddenCheck(tmp)) {
82+
qInfo() << "autostart application " << id << " couldn't pass check:" << desktopFile.sourcePath();
83+
continue;
84+
}
8185

82-
launchApplication(desktopFile);
86+
launchApplication(desktopFile);
87+
}
8388
}
8489
}
8590
} // namespace

src/applicationHooks.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
1+
// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
22
//
33
// SPDX-License-Identifier: LGPL-3.0-or-later
44

@@ -9,11 +9,10 @@
99
#include <QJsonObject>
1010
#include <QJsonParseError>
1111

12+
using namespace Qt::StringLiterals;
13+
1214
std::optional<ApplicationHook> ApplicationHook::loadFromFile(const QString &filePath) noexcept
1315
{
14-
auto index = filePath.lastIndexOf(QDir::separator());
15-
auto fileName = filePath.last(filePath.size() - index - 1);
16-
1716
QFile file{filePath};
1817
if (!file.open(QFile::Text | QFile::ReadOnly | QFile::ExistingOnly)) {
1918
qWarning() << "open hook file:" << filePath << "failed:" << file.errorString() << ", skip.";
@@ -33,26 +32,28 @@ std::optional<ApplicationHook> ApplicationHook::loadFromFile(const QString &file
3332
}
3433
auto obj = json.object();
3534

36-
auto it = obj.constFind("Exec");
35+
auto it = obj.constFind(u"Exec");
3736
if (it == obj.constEnd()) {
3837
qWarning() << "invalid hook: lack of Exec.";
3938
return std::nullopt;
4039
}
4140
auto exec = it->toString();
42-
QFileInfo info{exec};
43-
if (!(info.exists() and info.isExecutable())) {
41+
const QFileInfo info{exec};
42+
if (!(info.exists() && info.isExecutable())) {
4443
qWarning() << "exec maybe doesn't exists or be executed.";
4544
return std::nullopt;
4645
}
4746

48-
it = obj.constFind("Args");
47+
it = obj.constFind(u"Args");
4948
if (it == obj.constEnd()) {
5049
qWarning() << "invalid hook: lack of Args.";
5150
return std::nullopt;
5251
}
5352
auto args = it->toVariant().toStringList();
5453

55-
return ApplicationHook{std::move(fileName), std::move(exec), std::move(args)};
54+
auto fileName = file.fileName();
55+
auto lastSlash = fileName.lastIndexOf(QDir::separator());
56+
return ApplicationHook{fileName.slice(lastSlash + 1), std::move(exec), std::move(args)};
5657
}
5758

5859
QStringList generateHooks(const QList<ApplicationHook> &hooks) noexcept

src/applicationHooks.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
1+
// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
22
//
33
// SPDX-License-Identifier: LGPL-3.0-or-later
44

@@ -23,8 +23,8 @@ class ApplicationHook
2323
friend bool operator!=(const ApplicationHook &lhs, const ApplicationHook &rhs) { return !(lhs == rhs); };
2424

2525
private:
26-
ApplicationHook(QString &&hookName, QString &&execPath, QStringList &&args)
27-
: m_hookName(hookName)
26+
ApplicationHook(QString hookName, QString execPath, QStringList &&args)
27+
: m_hookName(std::move(hookName))
2828
, m_execPath(std::move(execPath))
2929
, m_args(std::move(args))
3030
{

src/applicationchecker.cpp

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//
33
// SPDX-License-Identifier: LGPL-3.0-or-later
44

5+
#include "global.h"
56
#include "constant.h"
67
#include "applicationchecker.h"
78
#include <QDir>
@@ -15,24 +16,34 @@ namespace {
1516

1617
bool hasDesktopIntersection(QStringView rawValue, const QStringList &currentDesktops) noexcept
1718
{
18-
if (rawValue.isEmpty()) {
19+
if (rawValue.isEmpty() || currentDesktops.isEmpty()) {
1920
return false;
2021
}
2122

22-
auto tokens = qTokenize(rawValue, u';', Qt::SkipEmptyParts);
23+
const auto &dde = fromStaticRaw(DesktopDDE);
24+
const auto &deepin = fromStaticRaw(DesktopDeepin);
25+
26+
bool currentHasDDE{false};
27+
for (const auto &s : currentDesktops) {
28+
if (s.compare(dde, Qt::CaseInsensitive) == 0 || s.compare(deepin, Qt::CaseInsensitive) == 0) {
29+
currentHasDDE = true;
30+
break;
31+
}
32+
}
2333

34+
auto tokens = qTokenize(rawValue, u';', Qt::SkipEmptyParts);
2435
for (const auto token : tokens) {
25-
const bool isDDE =
26-
(token.compare(u"DDE"_sv, Qt::CaseInsensitive) == 0 || token.compare(u"deepin"_sv, Qt::CaseInsensitive) == 0);
36+
const bool tokenIsDDE = (token.compare(dde, Qt::CaseInsensitive) == 0 || token.compare(deepin, Qt::CaseInsensitive) == 0);
2737

28-
for (const auto &current : currentDesktops) {
29-
if (isDDE) {
30-
if (current.compare(u"DDE"_sv, Qt::CaseInsensitive) == 0 ||
31-
current.compare(u"deepin"_sv, Qt::CaseInsensitive) == 0) {
38+
if (tokenIsDDE) {
39+
if (currentHasDDE) {
40+
return true;
41+
}
42+
} else {
43+
for (const auto &current : currentDesktops) {
44+
if (current.compare(token, Qt::CaseInsensitive) == 0) {
3245
return true;
3346
}
34-
} else if (current.compare(token, Qt::CaseInsensitive) == 0) {
35-
return true;
3647
}
3748
}
3849
}
@@ -51,7 +62,7 @@ bool ApplicationFilter::hiddenCheck(const DesktopEntry &entry) noexcept
5162
bool ok{false};
5263
hidden = toBoolean(hiddenVal.value(), ok);
5364
if (!ok) {
54-
qCWarning(DDEAMChecker) << "invalid hidden value:" << hiddenVal.value();
65+
qCWarning(DDEAMChecker) << "invalid hidden value:" << hiddenVal.value().get();
5566
return false;
5667
}
5768
}
@@ -60,11 +71,11 @@ bool ApplicationFilter::hiddenCheck(const DesktopEntry &entry) noexcept
6071

6172
bool ApplicationFilter::tryExecCheck(const DesktopEntry &entry) noexcept
6273
{
63-
auto tryExecVal = entry.value(fromStaticRaw(DesktopFileEntryKey), u"TryExec"_s);
74+
auto tryExecVal = entry.value(fromStaticRaw(DesktopFileEntryKey), fromStaticRaw(DesktopEntryTryExec));
6475
if (tryExecVal.has_value()) {
6576
auto executable = toString(tryExecVal.value());
6677
if (executable.isEmpty()) {
67-
qCWarning(DDEAMChecker) << "invalid TryExec value:" << tryExecVal.value();
78+
qCWarning(DDEAMChecker) << "invalid TryExec value:" << tryExecVal.value().get();
6879
return false;
6980
}
7081

@@ -86,12 +97,12 @@ bool ApplicationFilter::showInCheck(const DesktopEntry &entry) noexcept
8697
}
8798

8899
bool showInCurrentDE{true};
89-
if (auto val = entry.value(fromStaticRaw(DesktopFileEntryKey), u"OnlyShowIn"_s); val.has_value()) {
100+
if (auto val = entry.value(fromStaticRaw(DesktopFileEntryKey), fromStaticRaw(DesktopEntryOnlyShowIn)); val.has_value()) {
90101
showInCurrentDE = hasDesktopIntersection(toString(val.value()), desktops);
91102
}
92103

93104
bool notShowInCurrentDE{false};
94-
if (auto val = entry.value(fromStaticRaw(DesktopFileEntryKey), u"NotShowIn"_s); val.has_value()) {
105+
if (auto val = entry.value(fromStaticRaw(DesktopFileEntryKey), fromStaticRaw(DesktopEntryNotShowIn)); val.has_value()) {
95106
notShowInCurrentDE = hasDesktopIntersection(toString(val.value()), desktops);
96107
}
97108

0 commit comments

Comments
 (0)