Skip to content

Commit 24823b0

Browse files
committed
Fix XDG desktop entries shadowing behavior
1 parent e34a086 commit 24823b0

File tree

4 files changed

+66
-28
lines changed

4 files changed

+66
-28
lines changed

applications/src/xdg/application.cpp

+14-8
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,25 @@ Application::Application(const QString &id, const QString &path, ParseOptions po
2424
// NoDisplay - boolean, must not be true
2525
try {
2626
if (p.getBoolean(root_section, QStringLiteral("NoDisplay")))
27-
throw runtime_error("Desktop entry excluded by 'NoDisplay'.");
27+
exclude_reason_ = ExcludeReason::NoDisplay;
2828
} catch (const out_of_range &) { }
2929

30-
if (!po.ignore_show_in_keys)
30+
if (!po.ignore_show_in_keys && exclude_reason_ == ExcludeReason::None)
3131
{
3232
const auto desktops(QString(getenv("XDG_CURRENT_DESKTOP")).split(':', Qt::SkipEmptyParts));
3333

3434
// NotShowIn - string(s), if exists must not be in XDG_CURRENT_DESKTOP
3535
try {
3636
if (ranges::any_of(p.getString(root_section, QStringLiteral("NotShowIn")).split(';', Qt::SkipEmptyParts),
3737
[&](const auto &de){ return desktops.contains(de); }))
38-
throw runtime_error("Desktop entry excluded by 'NotShowIn'.");
38+
exclude_reason_ = ExcludeReason::NotShowIn;
3939
} catch (const out_of_range &) { }
4040

4141
// OnlyShowIn - string(s), if exists has to be in XDG_CURRENT_DESKTOP
4242
try {
4343
if (!ranges::any_of(p.getString(root_section, QStringLiteral("OnlyShowIn")).split(';', Qt::SkipEmptyParts),
4444
[&](const auto &de){ return desktops.contains(de); }))
45-
throw runtime_error("Desktop entry excluded by 'OnlyShowIn'.");
45+
exclude_reason_ = ExcludeReason::OnlyShowIn;
4646
} catch (const out_of_range &) { }
4747
}
4848

@@ -54,19 +54,20 @@ Application::Application(const QString &id, const QString &path, ParseOptions po
5454
if (po.use_non_localized_name)
5555
names_ << p.getString(root_section, QStringLiteral("Name"));
5656

57-
// Exec - string, REQUIRED despite not strictly by standard
57+
// Exec - string
5858
try
5959
{
6060
exec_ = DesktopEntryParser::splitExec(p.getString(root_section, QStringLiteral("Exec"))).value();
61-
if (exec_.isEmpty())
62-
throw runtime_error("Empty Exec value.");
6361
}
62+
catch (const out_of_range &) { }
6463
catch (const bad_optional_access&)
6564
{
6665
throw runtime_error("Malformed Exec value.");
6766
}
67+
if (exec_.isEmpty() && exclude_reason_ == ExcludeReason::None)
68+
exclude_reason_ = ExcludeReason::EmptyExec;
6869

69-
if (po.use_exec)
70+
if (po.use_exec && !exec_.isEmpty())
7071
{
7172
static QStringList excludes = {
7273
"/",
@@ -197,6 +198,11 @@ vector<Action> Application::actions() const
197198
return actions;
198199
}
199200

201+
const Application::ExcludeReason &Application::excludeReason() const
202+
{
203+
return exclude_reason_;
204+
}
205+
200206
const QStringList &Application::exec() const
201207
{
202208
return exec_;

applications/src/xdg/application.h

+11
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ class Application : public ApplicationBase
1919
bool use_non_localized_name;
2020
};
2121

22+
enum class ExcludeReason
23+
{
24+
None,
25+
NoDisplay,
26+
NotShowIn,
27+
OnlyShowIn,
28+
EmptyExec,
29+
};
30+
2231
Application(const QString &id, const QString &path, ParseOptions po);
2332
Application(const Application &) = default;
2433

@@ -28,6 +37,7 @@ class Application : public ApplicationBase
2837
std::vector<albert::Action> actions() const override final;
2938

3039
const QStringList &exec() const;
40+
const ExcludeReason &excludeReason() const;
3141

3242
protected:
3343

@@ -51,5 +61,6 @@ class Application : public ApplicationBase
5161
QString working_dir_;
5262
std::vector<DesktopAction> desktop_actions_;
5363
bool term_ = false;
64+
ExcludeReason exclude_reason_ = ExcludeReason::None;
5465

5566
};

applications/src/xdg/desktopentryparser.cpp

+9-10
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,17 @@ QString DesktopEntryParser::getRawValue(const QString &section, const QString &k
3838
class SectionDoesNotExist : public std::out_of_range { using out_of_range::out_of_range; };
3939
class KeyDoesNotExist : public std::out_of_range { using out_of_range::out_of_range; };
4040

41-
try {
42-
auto &s = data.at(section);
43-
try {
44-
return s.at(key);
45-
} catch (const out_of_range&) {
46-
throw KeyDoesNotExist(QString("Section '%1' does not contain a key '%2'.")
47-
.arg(section, key).toStdString());
48-
}
49-
} catch (const out_of_range&) {
41+
auto s = data.find(section);
42+
if (s == data.end())
5043
throw SectionDoesNotExist(QString("Desktop entry does not contain a section '%1'.")
5144
.arg(section).toStdString());
52-
}
45+
46+
auto v = s->second.find(key);
47+
if (v == s->second.end())
48+
throw KeyDoesNotExist(QString("Section '%1' does not contain a key '%2'.")
49+
.arg(section, key).toStdString());
50+
51+
return v->second;
5352
}
5453

5554
QString DesktopEntryParser::getEscapedValue(const QString &section, const QString &key) const

applications/src/xdg/plugin.cpp

+32-10
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ Plugin::Plugin()
116116
};
117117

118118
// Get a map of unique desktop entries according to the spec
119-
map<QString, shared_ptr<applications::Application>> apps; // Desktop id > path
119+
map<QString, QString> known_apps; // Desktop id > path
120+
vector<shared_ptr<applications::Application>> apps;
120121
for (const QString &dir : appDirectories())
121122
{
122123
DEBG << "Scanning desktop entries in:" << dir;
@@ -137,24 +138,45 @@ Plugin::Plugin()
137138
static const QRegularExpression re("^.*applications/");
138139
const auto id = fIt.filePath().remove(re).replace("/","-").chopped(8).toLower(); // '.desktop'
139140

141+
if (auto known_app = known_apps.find(id); known_app != known_apps.end())
142+
{
143+
DEBG << QString("Skipped '%1': Shadowed by '%2'").arg(path, known_app->second);
144+
continue;
145+
}
146+
140147
try
141148
{
142-
if (const auto &[it, success] = apps.emplace(id, make_shared<Application>(id, path, po));
143-
success)
144-
DEBG << QString("Valid desktop file '%1': '%2'").arg(path, it->second->name());
145-
else
146-
DEBG << QString("Skipped %1: Shadowed by '%2'").arg(path, it->second->path());
149+
const auto app = make_shared<Application>(id, path, po);
150+
known_apps[id] = path;
151+
152+
switch (app->excludeReason())
153+
{
154+
case Application::ExcludeReason::None:
155+
apps.push_back(app);
156+
DEBG << QString("Valid desktop file '%1': '%2'").arg(path, app->name());
157+
break;
158+
case Application::ExcludeReason::NoDisplay:
159+
DEBG << QString("Skipped '%1': Desktop entry excluded by 'NoDisplay'.").arg(path);
160+
break;
161+
case Application::ExcludeReason::NotShowIn:
162+
DEBG << QString("Skipped '%1': Desktop entry excluded by 'NotShowIn'.").arg(path);
163+
break;
164+
case Application::ExcludeReason::OnlyShowIn:
165+
DEBG << QString("Skipped '%1': Desktop entry excluded by 'OnlyShowIn'.").arg(path);
166+
break;
167+
case Application::ExcludeReason::EmptyExec:
168+
DEBG << QString("Skipped '%1': Empty Exec value.").arg(path);
169+
break;
170+
}
147171
}
148172
catch (const exception &e)
149173
{
150-
DEBG << QString("Skipped %1: %2").arg(path, e.what());
174+
DEBG << QString("Invalid desktop file '%1': %2").arg(path, e.what());
151175
}
152176
}
153177
}
154178

155-
vector<shared_ptr<applications::Application>> ret;
156-
ranges::move(apps | ranges::views::values, back_inserter(ret));
157-
return ret;
179+
return apps;
158180
};
159181

160182
indexer.finish = [this](vector<shared_ptr<applications::Application>> &&result)

0 commit comments

Comments
 (0)