KService

kservice.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1999-2001 Waldo Bastian <bastian@kde.org>
4 SPDX-FileCopyrightText: 1999-2005 David Faure <faure@kde.org>
5 SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-only
8*/
9
10#include "kservice.h"
11#include "kmimetypefactory_p.h"
12#include "kservice_p.h"
13#include "ksycoca.h"
14#include "ksycoca_p.h"
15
16#include <qplatformdefs.h>
17
18#include <QDir>
19#include <QMap>
20#include <QMimeDatabase>
21
22#include <KConfigGroup>
23#include <KDesktopFile>
24#include <KShell>
25
26#include <QDebug>
27#include <QStandardPaths>
28
29#include "kservicefactory_p.h"
30#include "kserviceutil_p.h"
31#include "servicesdebug.h"
32
33void KServicePrivate::init(const KDesktopFile *config, KService *q)
34{
35 const QString entryPath = q->entryPath();
36 if (entryPath.isEmpty()) {
37 // We are opening a "" service, this means whatever warning we might get is going to be misleading
38 m_bValid = false;
39 return;
40 }
41
42 bool absPath = !QDir::isRelativePath(entryPath);
43
44 const KConfigGroup desktopGroup = config->desktopGroup();
45 QMap<QString, QString> entryMap = desktopGroup.entryMap();
46
47 entryMap.remove(QStringLiteral("Encoding")); // reserved as part of Desktop Entry Standard
48 entryMap.remove(QStringLiteral("Version")); // reserved as part of Desktop Entry Standard
49
50 q->setDeleted(desktopGroup.readEntry("Hidden", false));
51 entryMap.remove(QStringLiteral("Hidden"));
52 if (q->isDeleted()) {
53 m_bValid = false;
54 return;
55 }
56
57 m_strName = config->readName();
58 entryMap.remove(QStringLiteral("Name"));
59 if (m_strName.isEmpty()) {
60 // Try to make up a name.
61 m_strName = entryPath;
62 int i = m_strName.lastIndexOf(QLatin1Char('/'));
63 m_strName = m_strName.mid(i + 1);
64 i = m_strName.lastIndexOf(QLatin1Char('.'));
65 if (i != -1) {
66 m_strName.truncate(i);
67 }
68 }
69
70 m_strType = entryMap.take(QStringLiteral("Type"));
71 if (m_strType.isEmpty()) {
72 qCWarning(SERVICES) << "The desktop entry file" << entryPath << "does not have a \"Type=Application\" set.";
73 m_strType = QStringLiteral("Application");
74 } else if (m_strType != QLatin1String("Application") && m_strType != QLatin1String("Service")) {
75 qCWarning(SERVICES) << "The desktop entry file" << entryPath << "has Type=" << m_strType << "instead of \"Application\" or \"Service\"";
76 m_bValid = false;
77 return;
78 }
79
80 // NOT readPathEntry, it is not XDG-compliant: it performs
81 // various expansions, like $HOME. Note that the expansion
82 // behaviour still happens if the "e" flag is set, maintaining
83 // backwards compatibility.
84 m_strExec = entryMap.take(QStringLiteral("Exec"));
85
86 // In case Try Exec is set, check if the application is available
87 if (!config->tryExec()) {
88 q->setDeleted(true);
89 m_bValid = false;
90 return;
91 }
92
93 const QStandardPaths::StandardLocation locationType = config->locationType();
94
95 if ((m_strType == QLatin1String("Application")) && (locationType != QStandardPaths::ApplicationsLocation) && !absPath) {
96 qCWarning(SERVICES) << "The desktop entry file" << entryPath << "has Type=" << m_strType << "but is located under \""
97 << QStandardPaths::displayName(locationType) << "\" instead of \"Applications\"";
98 m_bValid = false;
99 return;
100 }
101
102 // entryPath To desktopEntryName
103 // (e.g. "/usr/share/applications/org.kde.kate" --> "org.kde.kate")
104 QString _name = KServiceUtilPrivate::completeBaseName(entryPath);
105
106 m_strIcon = entryMap.take(QStringLiteral("Icon"));
107 m_bTerminal = desktopGroup.readEntry("Terminal", false);
108 entryMap.remove(QStringLiteral("Terminal"));
109 m_strTerminalOptions = entryMap.take(QStringLiteral("TerminalOptions"));
110 m_strWorkingDirectory = KShell::tildeExpand(entryMap.take(QStringLiteral("Path")));
111 m_strComment = entryMap.take(QStringLiteral("Comment"));
112 m_strGenName = entryMap.take(QStringLiteral("GenericName"));
113
114 // Store these as member variables too, because the lookup will be significanly faster
115 m_untranslatedGenericName = desktopGroup.readEntryUntranslated("GenericName");
116 m_untranslatedName = desktopGroup.readEntryUntranslated("Name");
117
118 m_lstFormFactors = entryMap.take(QStringLiteral("X-KDE-FormFactors")).split(QLatin1Char(' '), Qt::SkipEmptyParts);
119
120 if (entryMap.remove(QStringLiteral("Keywords"))) {
121 m_lstKeywords = desktopGroup.readXdgListEntry("Keywords");
122 }
123 m_lstKeywords += entryMap.take(QStringLiteral("X-KDE-Keywords")).split(QLatin1Char(' '), Qt::SkipEmptyParts);
124 if (entryMap.remove(QStringLiteral("Categories"))) {
125 categories = desktopGroup.readXdgListEntry("Categories");
126 }
127
128 if (entryMap.remove(QStringLiteral("MimeType"))) {
129 m_mimeTypes = desktopGroup.readXdgListEntry("MimeType");
130 }
131
132 m_strDesktopEntryName = _name;
133
134 if (entryMap.remove(QStringLiteral("AllowDefault"))) {
135 m_bAllowAsDefault = desktopGroup.readEntry("AllowDefault", true);
136 }
137
138 // Store all additional entries in the property map.
139 // A QMap<QString,QString> would be easier for this but we can't
140 // break BC, so we have to store it in m_mapProps.
141 // qDebug("Path = %s", entryPath.toLatin1().constData());
142 auto it = entryMap.constBegin();
143 for (; it != entryMap.constEnd(); ++it) {
144 const QString key = it.key();
145
146 // Ignore Actions, we parse that below
147 if (key == QLatin1String("Actions")) {
148 continue;
149 }
150
151 // do not store other translations like Name[fr]; kbuildsycoca will rerun if we change languages anyway
152 if (!key.contains(QLatin1Char('['))) {
153 // qCDebug(SERVICES) << " Key =" << key << " Data =" << it.value();
154 if (key == QLatin1String("X-Flatpak-RenamedFrom")) {
155 m_mapProps.insert(key, desktopGroup.readXdgListEntry(key));
156 } else {
157 m_mapProps.insert(key, QVariant(it.value()));
158 }
159 }
160 }
161
162 // parse actions last since that may clone the service
163 // we want all other information parsed by then
164 if (entryMap.contains(QLatin1String("Actions"))) {
165 parseActions(config, q);
166 }
167}
168
169void KServicePrivate::parseActions(const KDesktopFile *config, KService *q)
170{
171 const QStringList keys = config->readActions();
172 if (keys.isEmpty()) {
173 return;
174 }
175
176 KService::Ptr serviceClone(new KService(*q));
177
178 for (const QString &group : keys) {
179 if (group == QLatin1String("_SEPARATOR_")) {
180 m_actions.append(KServiceAction(group, QString(), QString(), QString(), false, serviceClone));
181 continue;
182 }
183
184 if (config->hasActionGroup(group)) {
185 const KConfigGroup cg = config->actionGroup(group);
186 if (!cg.hasKey("Name")) {
187 qCWarning(SERVICES) << "The action" << group << "in the desktop file" << q->entryPath() << "has no Name key";
188 } else if (!cg.hasKey("Exec") && !config->desktopGroup().readEntry("DBusActivatable", false)) {
189 qCWarning(SERVICES) << "The action" << group << "in the desktop file" << q->entryPath() << "has no Exec key and not D-Bus activatable";
190 } else {
191 const QMap<QString, QString> entries = cg.entryMap();
192
193 QVariantMap entriesVariants;
194
195 for (auto it = entries.constKeyValueBegin(); it != entries.constKeyValueEnd(); ++it) {
196 // Those are stored separately
197 if (it->first == QLatin1String("Name") || it->first == QLatin1String("Icon") || it->first == QLatin1String("Exec")
198 || it->first == QLatin1String("NoDisplay")) {
199 continue;
200 }
201
202 entriesVariants.insert(it->first, it->second);
203 }
204
205 KServiceAction action(group, cg.readEntry("Name"), cg.readEntry("Icon"), cg.readEntry("Exec"), cg.readEntry("NoDisplay", false), serviceClone);
206 action.setData(QVariant::fromValue(entriesVariants));
207 m_actions.append(action);
208 }
209 } else {
210 qCWarning(SERVICES) << "The desktop file" << q->entryPath() << "references the action" << group << "but doesn't define it";
211 }
212 }
213
214 serviceClone->setActions(m_actions);
215}
216
217void KServicePrivate::load(QDataStream &s)
218{
219 qint8 def;
220 qint8 term;
221 qint8 dst;
222
223 // WARNING: THIS NEEDS TO REMAIN COMPATIBLE WITH PREVIOUS KService 6.x VERSIONS!
224 // !! This data structure should remain binary compatible at all times !!
225 // You may add new fields at the end. Make sure to update KSYCOCA_VERSION
226 // number in ksycoca.cpp
227 // clang-format off
228 s >> m_strType >> m_strName >> m_strExec >> m_strIcon
229 >> term >> m_strTerminalOptions
230 >> m_strWorkingDirectory >> m_strComment >> def >> m_mapProps
231 >> m_strLibrary
232 >> dst
233 >> m_strDesktopEntryName
234 >> m_lstKeywords >> m_strGenName
235 >> categories >> menuId >> m_actions
236 >> m_lstFormFactors
237 >> m_untranslatedName >> m_untranslatedGenericName >> m_mimeTypes;
238 // clang-format on
239
240 m_bAllowAsDefault = bool(def);
241 m_bTerminal = bool(term);
242
243 m_bValid = true;
244}
245
246void KServicePrivate::save(QDataStream &s)
247{
248 KSycocaEntryPrivate::save(s);
249 qint8 def = m_bAllowAsDefault;
250 qint8 term = m_bTerminal;
251 qint8 dst = 0;
252
253 // WARNING: THIS NEEDS TO REMAIN COMPATIBLE WITH PREVIOUS KService 6.x VERSIONS!
254 // !! This data structure should remain binary compatible at all times !!
255 // You may add new fields at the end. Make sure to update KSYCOCA_VERSION
256 // number in ksycoca.cpp
257 s << m_strType << m_strName << m_strExec << m_strIcon << term << m_strTerminalOptions << m_strWorkingDirectory << m_strComment << def << m_mapProps
258 << m_strLibrary << dst << m_strDesktopEntryName << m_lstKeywords << m_strGenName << categories << menuId << m_actions << m_lstFormFactors
259 << m_untranslatedName << m_untranslatedGenericName << m_mimeTypes;
260}
261
262////
263
264KService::KService(const QString &_name, const QString &_exec, const QString &_icon)
265 : KSycocaEntry(*new KServicePrivate(QString()))
266{
267 Q_D(KService);
268 d->m_strType = QStringLiteral("Application");
269 d->m_strName = _name;
270 d->m_strExec = _exec;
271 d->m_strIcon = _icon;
272 d->m_bTerminal = false;
273 d->m_bAllowAsDefault = true;
274}
275
277 : KSycocaEntry(*new KServicePrivate(_fullpath))
278{
279 Q_D(KService);
280
281 KDesktopFile config(_fullpath);
282 d->init(&config, this);
283}
284
286 : KSycocaEntry(*new KServicePrivate(entryPath.isEmpty() ? config->fileName() : entryPath))
287{
288 Q_D(KService);
289
290 d->init(config, this);
291}
292
293KService::KService(QDataStream &_str, int _offset)
294 : KSycocaEntry(*new KServicePrivate(_str, _offset))
295{
296 Q_D(KService);
297 KService::Ptr serviceClone(new KService(*this));
298 for (KServiceAction &action : d->m_actions) {
299 action.setService(serviceClone);
300 }
301}
302
303KService::KService(const KService &other)
304 : KSycocaEntry(*new KServicePrivate(*other.d_func()))
305{
306}
307
308KService::~KService()
309{
310}
311
312bool KService::hasMimeType(const QString &mimeType) const
313{
314 Q_D(const KService);
315 QMimeDatabase db;
316 const QString mime = db.mimeTypeForName(mimeType).name();
317 if (mime.isEmpty()) {
318 return false;
319 }
320 int serviceOffset = offset();
321 if (serviceOffset) {
323 KMimeTypeFactory *factory = KSycocaPrivate::self()->mimeTypeFactory();
324 const int mimeOffset = factory->entryOffset(mime);
325 const int serviceOffersOffset = factory->serviceOffersOffset(mime);
326 if (serviceOffersOffset == -1) {
327 return false;
328 }
329 return KSycocaPrivate::self()->serviceFactory()->hasOffer(mimeOffset, serviceOffersOffset, serviceOffset);
330 }
331
332 return d->m_mimeTypes.contains(mime);
333}
334
336{
337 Q_D(const KService);
338 return d->property(_name, t);
339}
340
341template<>
343{
344 Q_D(const KService);
345
346 if (_name == QLatin1String("Type")) {
347 return d->m_strType;
348 } else if (_name == QLatin1String("Name")) {
349 return d->m_strName;
350 } else if (_name == QLatin1String("Exec")) {
351 return d->m_strExec;
352 } else if (_name == QLatin1String("Icon")) {
353 return d->m_strIcon;
354 } else if (_name == QLatin1String("TerminalOptions")) {
355 return d->m_strTerminalOptions;
356 } else if (_name == QLatin1String("Path")) {
357 return d->m_strWorkingDirectory;
358 } else if (_name == QLatin1String("Comment")) {
359 return d->m_strComment;
360 } else if (_name == QLatin1String("GenericName")) {
361 return d->m_strGenName;
362 } else if (_name == QLatin1String("DesktopEntryPath")) {
363 return d->path;
364 } else if (_name == QLatin1String("DesktopEntryName")) {
365 return d->m_strDesktopEntryName;
366 } else if (_name == QLatin1String("UntranslatedName")) {
367 return d->m_untranslatedName;
368 } else if (_name == QLatin1String("UntranslatedGenericName")) {
369 return d->m_untranslatedGenericName;
370 }
371
372 auto it = d->m_mapProps.constFind(_name);
373
374 if (it != d->m_mapProps.cend()) {
375 return it.value().toString();
376 }
377
378 return QString();
379}
380
381QVariant KServicePrivate::property(const QString &_name, QMetaType::Type t) const
382{
383 if (_name == QLatin1String("Terminal")) {
384 return QVariant(m_bTerminal);
385 } else if (_name == QLatin1String("AllowAsDefault")) {
386 return QVariant(m_bAllowAsDefault);
387 } else if (_name == QLatin1String("Categories")) {
388 return QVariant(categories);
389 } else if (_name == QLatin1String("Keywords")) {
390 return QVariant(m_lstKeywords);
391 } else if (_name == QLatin1String("FormFactors")) {
392 return QVariant(m_lstFormFactors);
393 }
394
395 auto it = m_mapProps.constFind(_name);
396 if (it == m_mapProps.cend() || !it.value().isValid()) {
397 // qCDebug(SERVICES) << "Property not found " << _name;
398 return QVariant(); // No property set.
399 }
400
401 if (it->typeId() == t) {
402 return it.value(); // no conversion necessary
403 } else {
404 // All others
405 // For instance properties defined as StringList, like MimeTypes.
406 // XXX This API is accessible only through a friend declaration.
407 return KConfigGroup::convertToQVariant(_name.toUtf8().constData(), it.value().toString().toUtf8(), QVariant(QMetaType(t)));
408 }
409}
410
412{
414 return KSycocaPrivate::self()->serviceFactory()->allServices();
415}
416
418{
420 return KSycocaPrivate::self()->serviceFactory()->findServiceByDesktopPath(_name);
421}
422
424{
426 return KSycocaPrivate::self()->serviceFactory()->findServiceByDesktopName(_name);
427}
428
430{
432 return KSycocaPrivate::self()->serviceFactory()->findServiceByMenuId(_name);
433}
434
436{
438 return KSycocaPrivate::self()->serviceFactory()->findServiceByStorageId(_storageId);
439}
440
442{
443 return property<bool>(QStringLiteral("X-KDE-SubstituteUID"));
444}
445
447{
448 // See also KDesktopFile::tryExec()
449 QString user = property<QString>(QStringLiteral("X-KDE-Username"));
450 if (user.isEmpty()) {
451 user = QString::fromLocal8Bit(qgetenv("ADMIN_ACCOUNT"));
452 }
453 if (user.isEmpty()) {
454 user = QStringLiteral("root");
455 }
456 return user;
457}
458
460{
461 Q_D(const KService);
462
463 const QString envVar = QString::fromLatin1(qgetenv("XDG_CURRENT_DESKTOP"));
464
465 QList<QStringView> currentDesktops = QStringView(envVar).split(QLatin1Char(':'), Qt::SkipEmptyParts);
466
467 const QString kde = QStringLiteral("KDE");
468 if (currentDesktops.isEmpty()) {
469 // This could be an old display manager, or e.g. a failsafe session with no desktop name
470 // In doubt, let's say we show KDE stuff.
471 currentDesktops.append(kde);
472 }
473
474 // This algorithm is described in the desktop entry spec
475
476 auto it = d->m_mapProps.constFind(QStringLiteral("OnlyShowIn"));
477 if (it != d->m_mapProps.cend()) {
478 const QVariant &val = it.value();
479 if (val.isValid()) {
480 const QStringList aList = val.toString().split(QLatin1Char(';'));
481 return std::any_of(currentDesktops.cbegin(), currentDesktops.cend(), [&aList](const auto desktop) {
482 return aList.contains(desktop);
483 });
484 }
485 }
486
487 it = d->m_mapProps.constFind(QStringLiteral("NotShowIn"));
488 if (it != d->m_mapProps.cend()) {
489 const QVariant &val = it.value();
490 if (val.isValid()) {
491 const QStringList aList = val.toString().split(QLatin1Char(';'));
492 return std::none_of(currentDesktops.cbegin(), currentDesktops.cend(), [&aList](const auto desktop) {
493 return aList.contains(desktop);
494 });
495 }
496 }
497
498 return true;
499}
500
502{
503 Q_D(const KService);
504 const QString platform = QCoreApplication::instance()->property("platformName").toString();
505 if (platform.isEmpty()) {
506 return true;
507 }
508
509 auto it = d->m_mapProps.find(QStringLiteral("X-KDE-OnlyShowOnQtPlatforms"));
510 if ((it != d->m_mapProps.end()) && (it->isValid())) {
511 const QStringList aList = it->toString().split(QLatin1Char(';'));
512 if (!aList.contains(platform)) {
513 return false;
514 }
515 }
516
517 it = d->m_mapProps.find(QStringLiteral("X-KDE-NotShowOnQtPlatforms"));
518 if ((it != d->m_mapProps.end()) && (it->isValid())) {
519 const QStringList aList = it->toString().split(QLatin1Char(';'));
520 if (aList.contains(platform)) {
521 return false;
522 }
523 }
524 return true;
525}
526
528{
529 if (property<bool>(QStringLiteral("NoDisplay"))) {
530 return true;
531 }
532
533 if (!showInCurrentDesktop()) {
534 return true;
535 }
536
537 if (!showOnCurrentPlatform()) {
538 return true;
539 }
540 return false;
541}
542
544{
545 Q_D(const KService);
546 return d->m_untranslatedGenericName;
547}
548
550{
551 Q_D(const KService);
552 return d->m_untranslatedName;
553}
554
556{
557 Q_D(const KService);
558
559 for (const QString &str : {QStringLiteral("X-DocPath"), QStringLiteral("DocPath")}) {
560 auto it = d->m_mapProps.constFind(str);
561 if (it != d->m_mapProps.cend()) {
562 const QVariant variant = it.value();
563 Q_ASSERT(variant.isValid());
564 const QString path = variant.toString();
565 if (!path.isEmpty()) {
566 return path;
567 }
568 }
569 }
570
571 return {};
572}
573
575{
576 Q_D(const KService);
577 // Can we pass multiple files on the command line or do we have to start the application for every single file ?
578 return (d->m_strExec.contains(QLatin1String("%F")) //
579 || d->m_strExec.contains(QLatin1String("%U")) //
580 || d->m_strExec.contains(QLatin1String("%N")) //
581 || d->m_strExec.contains(QLatin1String("%D")));
582}
583
585{
586 Q_D(const KService);
587 return d->categories;
588}
589
591{
592 Q_D(const KService);
593 return d->menuId;
594}
595
596void KService::setMenuId(const QString &_menuId)
597{
598 Q_D(KService);
599 d->menuId = _menuId;
600}
601
603{
604 Q_D(const KService);
605 return d->storageId();
606}
607
608// not sure this is still used anywhere...
610{
611 Q_D(const KService);
612 if (d->menuId.isEmpty() //
613 || entryPath().startsWith(QLatin1String(".hidden")) //
614 || (QDir::isRelativePath(entryPath()) && d->categories.isEmpty())) {
616 }
617
619}
620
621QString KService::newServicePath(bool showInMenu, const QString &suggestedName, QString *menuId, const QStringList *reservedMenuIds)
622{
623 Q_UNUSED(showInMenu); // TODO KDE5: remove argument
624
625 QString base = suggestedName;
626 QString result;
627 for (int i = 1; true; i++) {
628 if (i == 1) {
629 result = base + QStringLiteral(".desktop");
630 } else {
631 result = base + QStringLiteral("-%1.desktop").arg(i);
632 }
633
634 if (reservedMenuIds && reservedMenuIds->contains(result)) {
635 continue;
636 }
637
638 // Lookup service by menu-id
639 KService::Ptr s = serviceByMenuId(result);
640 if (s) {
641 continue;
642 }
643
644 if (!QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("applications/") + result).isEmpty()) {
645 continue;
646 }
647
648 break;
649 }
650 if (menuId) {
651 *menuId = result;
652 }
653
655}
656
658{
659 Q_D(const KService);
660 return d->m_strType == QLatin1String("Application");
661}
662
664{
665 Q_D(const KService);
666 return d->m_strExec;
667}
668
670{
671 Q_D(const KService);
672 return d->m_strIcon;
673}
674
676{
677 Q_D(const KService);
678 return d->m_strTerminalOptions;
679}
680
682{
683 Q_D(const KService);
684 return d->m_bTerminal;
685}
686
688{
689 QVariant prop = property<bool>(QStringLiteral("PrefersNonDefaultGPU"));
690 if (!prop.isValid()) {
691 // For backwards compatibility
692 prop = property<bool>(QStringLiteral("X-KDE-RunOnDiscreteGpu"));
693 }
694
695 return prop.isValid() && prop.toBool();
696}
697
699{
700 Q_D(const KService);
701 return d->m_strDesktopEntryName;
702}
703
705{
706 Q_D(const KService);
707 return d->m_strWorkingDirectory;
708}
709
711{
712 Q_D(const KService);
713 return d->m_strComment;
714}
715
717{
718 Q_D(const KService);
719 return d->m_strGenName;
720}
721
723{
724 Q_D(const KService);
725 return d->m_lstKeywords;
726}
727
729{
730 Q_D(const KService);
731 QMimeDatabase db;
732 QStringList ret;
733
734 for (const auto &mimeName : d->m_mimeTypes) {
735 if (db.mimeTypeForName(mimeName).isValid()) { // keep only mimetypes, filter out servicetypes
736 ret.append(mimeName);
737 }
738 }
739 return ret;
740}
741
743{
744 Q_D(const KService);
745
746 QStringList ret;
747
748 const QLatin1String schemeHandlerPrefix("x-scheme-handler/");
749 for (const auto &mimeName : d->m_mimeTypes) {
750 if (mimeName.startsWith(schemeHandlerPrefix)) {
751 ret.append(mimeName.mid(schemeHandlerPrefix.size()));
752 }
753 }
754
755 return ret;
756}
757
759{
760 Q_D(const KService);
761
762 QStringList ret;
763
764 ret << schemeHandlers();
765
766 const QStringList protocols = property<QStringList>(QStringLiteral("X-KDE-Protocols"));
767 for (const QString &protocol : protocols) {
768 if (!ret.contains(protocol)) {
769 ret.append(protocol);
770 }
771 }
772
773 return ret;
774}
775
777{
778 Q_D(KService);
779 d->m_bTerminal = b;
780}
781
783{
784 Q_D(KService);
785 d->m_strTerminalOptions = options;
786}
787
789{
790 Q_D(KService);
791
792 if (!exec.isEmpty()) {
793 d->m_strExec = exec;
794 d->path.clear();
795 }
796}
797
799{
800 Q_D(KService);
801
802 if (!workingDir.isEmpty()) {
803 d->m_strWorkingDirectory = workingDir;
804 d->path.clear();
805 }
806}
807
809{
810 Q_D(const KService);
811 return d->m_actions;
812}
813
815{
816 return KServiceUtilPrivate::completeBaseName(property<QString>(QStringLiteral("X-KDE-AliasFor")));
817}
818
819void KService::setActions(const QList<KServiceAction> &actions)
820{
821 Q_D(KService);
822 d->m_actions = actions;
823}
824
825std::optional<bool> KService::startupNotify() const
826{
827 Q_D(const KService);
828
829 if (QVariant value = d->m_mapProps.value(QStringLiteral("StartupNotify")); value.isValid()) {
830 return value.toBool();
831 }
832
833 if (QVariant value = d->m_mapProps.value(QStringLiteral("X-KDE-StartupNotify")); value.isValid()) {
834 return value.toBool();
835 }
836
837 return {};
838}
QString readEntryUntranslated(const char *key, const QString &aDefault=QString()) const
bool hasKey(const char *key) const
QStringList readXdgListEntry(const char *key, const QStringList &aDefault=QStringList()) const
QString readEntry(const char *key, const char *aDefault=nullptr) const
QMap< QString, QString > entryMap() const
QStandardPaths::StandardLocation locationType() const
KConfigGroup actionGroup(const QString &group)
QString readName() const
bool tryExec() const
KConfigGroup desktopGroup() const
static QString locateLocal(const QString &path)
bool hasActionGroup(const QString &group) const
QStringList readActions() const
Represents an action in a .desktop file Actions are defined with the config key Actions in the [Deskt...
Represents an installed application.
Definition kservice.h:44
QStringList categories() const
Returns a list of VFolder categories.
Definition kservice.cpp:584
QStringList mimeTypes() const
Returns the list of MIME types that this application supports.
Definition kservice.cpp:728
static Ptr serviceByStorageId(const QString &_storageId)
Find a application by its storage-id or desktop-file path.
Definition kservice.cpp:435
void setExec(const QString &exec)
Overrides the "Exec=" line of the service.
Definition kservice.cpp:788
void setWorkingDirectory(const QString &workingDir)
Overrides the "Path=" line of the application.
Definition kservice.cpp:798
QString storageId() const
Returns a normalized ID suitable for storing in configuration files.
Definition kservice.cpp:602
QString desktopEntryName() const
Returns the filename of the desktop entry without any extension, e.g.
Definition kservice.cpp:698
QStringList keywords() const
Returns a list of descriptive keywords for the application, if there are any.
Definition kservice.cpp:722
void setTerminalOptions(const QString &options)
Definition kservice.cpp:782
QList< KServiceAction > actions() const
Returns the actions defined in this desktop file.
Definition kservice.cpp:808
static QString newServicePath(bool showInMenu, const QString &suggestedName, QString *menuId=nullptr, const QStringList *reservedMenuIds=nullptr)
Returns a path that can be used to create a new KService based on suggestedName.
Definition kservice.cpp:621
bool allowMultipleFiles() const
Checks whether this application can handle several files as startup arguments.
Definition kservice.cpp:574
QStringList supportedProtocols() const
Returns the list of protocols this application supports.
Definition kservice.cpp:758
QString genericName() const
Returns the generic name for the application, if there is one (e.g.
Definition kservice.cpp:716
bool substituteUid() const
Checks whether the application needs to run under a different UID.
Definition kservice.cpp:441
T property(const QString &name) const
Returns the requested property.
Definition kservice.h:321
bool terminal() const
Checks whether the application should be run in a terminal.
Definition kservice.cpp:681
QString terminalOptions() const
Returns any options associated with the terminal the application runs in, if it requires a terminal.
Definition kservice.cpp:675
static List allServices()
Returns the whole list of applications.
Definition kservice.cpp:411
KService(const QString &name, const QString &exec, const QString &icon)
Construct a temporary service with a given name, exec-line and icon.
Definition kservice.cpp:264
bool noDisplay() const
Whether the entry should be hidden from the menu.
Definition kservice.cpp:527
QString username() const
Returns the user name if the application runs with a different user id.
Definition kservice.cpp:446
QString aliasFor() const
A desktop file name that this application is an alias for.
Definition kservice.cpp:814
QString locateLocal() const
Returns a path that can be used for saving changes to this application.
Definition kservice.cpp:609
static Ptr serviceByDesktopName(const QString &_name)
Find an application by the name of its desktop file, not depending on its actual location (as long as...
Definition kservice.cpp:423
QString menuId() const
Returns the menu ID of the application desktop entry.
Definition kservice.cpp:590
bool showOnCurrentPlatform() const
Whether the application should be shown on the current platform (e.g.
Definition kservice.cpp:501
QString exec() const
Returns the executable.
Definition kservice.cpp:663
void setTerminal(bool b)
Definition kservice.cpp:776
QString comment() const
Returns the descriptive comment for the application, if there is one.
Definition kservice.cpp:710
QString untranslatedGenericName() const
Returns the untranslated (US English) generic name for the application, if there is one (e....
Definition kservice.cpp:543
QString untranslatedName() const
Definition kservice.cpp:549
QString icon() const
Returns the name of the icon.
Definition kservice.cpp:669
QStringList schemeHandlers() const
Returns the list of scheme handlers this application supports.
Definition kservice.cpp:742
void setMenuId(const QString &menuId)
Definition kservice.cpp:596
QString workingDirectory() const
Definition kservice.cpp:704
QString docPath() const
The path to the documentation for this application.
Definition kservice.cpp:555
std::optional< bool > startupNotify() const
Returns the value of StartupNotify for this service.
Definition kservice.cpp:825
static Ptr serviceByMenuId(const QString &_menuId)
Find a application by its menu-id.
Definition kservice.cpp:429
bool showInCurrentDesktop() const
Whether the application should be shown in the current desktop (including in context menus).
Definition kservice.cpp:459
bool isApplication() const
Whether this service is an application.
Definition kservice.cpp:657
QExplicitlySharedDataPointer< KService > Ptr
A shared data pointer for KService.
Definition kservice.h:49
static Ptr serviceByDesktopPath(const QString &_path)
Find a application based on its path as returned by entryPath().
Definition kservice.cpp:417
QList< Ptr > List
A list of shared data pointers for KService.
Definition kservice.h:53
bool hasMimeType(const QString &mimeType) const
Checks whether the application supports this MIME type.
Definition kservice.cpp:312
bool runOnDiscreteGpu() const
Returns true if the application indicates that it's preferred to run on a discrete graphics card,...
Definition kservice.cpp:687
Base class for all Sycoca entries.
bool isDeleted() const
QString entryPath() const
void setDeleted(bool deleted)
Sets whether or not this service is deleted.
static KSycoca * self()
Get or create the only instance of KSycoca (read-only)
Definition ksycoca.cpp:357
void ensureCacheValid()
Ensures the ksycoca database is up to date.
Definition ksycoca.cpp:763
KCOREADDONS_EXPORT QString tildeExpand(const QString &path)
const char * constData() const const
QCoreApplication * instance()
bool isRelativePath(const QString &path)
void append(QList< T > &&value)
const_iterator cbegin() const const
const_iterator cend() const const
bool isEmpty() const const
const_iterator constBegin() const const
const_iterator constEnd() const const
const_key_value_iterator constKeyValueBegin() const const
const_key_value_iterator constKeyValueEnd() const const
bool contains(const Key &key) const const
size_type remove(const Key &key)
T take(const Key &key)
QMimeType mimeTypeForName(const QString &nameOrAlias) const const
bool isValid() const const
QVariant property(const char *name) const const
QString displayName(StandardLocation type)
QString locate(StandardLocation type, const QString &fileName, LocateOptions options)
QString writableLocation(StandardLocation type)
QString arg(Args &&... args) const const
void clear()
QString fromLatin1(QByteArrayView str)
QString fromLocal8Bit(QByteArrayView str)
bool isEmpty() const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QByteArray toUtf8() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QList< QStringView > split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
SkipEmptyParts
QVariant fromValue(T &&value)
bool isValid() const const
bool toBool() const const
QString toString() const const
T value() const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Apr 25 2025 11:54:19 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.