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") || !cg.hasKey("Exec")) {
187 qCWarning(SERVICES) << "The action" << group << "in the desktop file" << q->entryPath() << "has no Name or no Exec key";
188 } else {
189 const QMap<QString, QString> entries = cg.entryMap();
190
191 QVariantMap entriesVariants;
192
193 for (auto it = entries.constKeyValueBegin(); it != entries.constKeyValueEnd(); ++it) {
194 // Those are stored separately
195 if (it->first == QLatin1String("Name") || it->first == QLatin1String("Icon") || it->first == QLatin1String("Exec")
196 || it->first == QLatin1String("NoDisplay")) {
197 continue;
198 }
199
200 entriesVariants.insert(it->first, it->second);
201 }
202
203 KServiceAction action(group, cg.readEntry("Name"), cg.readEntry("Icon"), cg.readEntry("Exec"), cg.readEntry("NoDisplay", false), serviceClone);
204 action.setData(QVariant::fromValue(entriesVariants));
205 m_actions.append(action);
206 }
207 } else {
208 qCWarning(SERVICES) << "The desktop file" << q->entryPath() << "references the action" << group << "but doesn't define it";
209 }
210 }
211
212 serviceClone->setActions(m_actions);
213}
214
215void KServicePrivate::load(QDataStream &s)
216{
217 qint8 def;
218 qint8 term;
219 qint8 dst;
220
221 // WARNING: THIS NEEDS TO REMAIN COMPATIBLE WITH PREVIOUS KService 6.x VERSIONS!
222 // !! This data structure should remain binary compatible at all times !!
223 // You may add new fields at the end. Make sure to update KSYCOCA_VERSION
224 // number in ksycoca.cpp
225 // clang-format off
226 s >> m_strType >> m_strName >> m_strExec >> m_strIcon
227 >> term >> m_strTerminalOptions
228 >> m_strWorkingDirectory >> m_strComment >> def >> m_mapProps
229 >> m_strLibrary
230 >> dst
231 >> m_strDesktopEntryName
232 >> m_lstKeywords >> m_strGenName
233 >> categories >> menuId >> m_actions
234 >> m_lstFormFactors
235 >> m_untranslatedName >> m_untranslatedGenericName >> m_mimeTypes;
236 // clang-format on
237
238 m_bAllowAsDefault = bool(def);
239 m_bTerminal = bool(term);
240
241 m_bValid = true;
242}
243
244void KServicePrivate::save(QDataStream &s)
245{
246 KSycocaEntryPrivate::save(s);
247 qint8 def = m_bAllowAsDefault;
248 qint8 term = m_bTerminal;
249 qint8 dst = 0;
250
251 // WARNING: THIS NEEDS TO REMAIN COMPATIBLE WITH PREVIOUS KService 6.x VERSIONS!
252 // !! This data structure should remain binary compatible at all times !!
253 // You may add new fields at the end. Make sure to update KSYCOCA_VERSION
254 // number in ksycoca.cpp
255 s << m_strType << m_strName << m_strExec << m_strIcon << term << m_strTerminalOptions << m_strWorkingDirectory << m_strComment << def << m_mapProps
256 << m_strLibrary << dst << m_strDesktopEntryName << m_lstKeywords << m_strGenName << categories << menuId << m_actions << m_lstFormFactors
257 << m_untranslatedName << m_untranslatedGenericName << m_mimeTypes;
258}
259
260////
261
262KService::KService(const QString &_name, const QString &_exec, const QString &_icon)
263 : KSycocaEntry(*new KServicePrivate(QString()))
264{
265 Q_D(KService);
266 d->m_strType = QStringLiteral("Application");
267 d->m_strName = _name;
268 d->m_strExec = _exec;
269 d->m_strIcon = _icon;
270 d->m_bTerminal = false;
271 d->m_bAllowAsDefault = true;
272}
273
275 : KSycocaEntry(*new KServicePrivate(_fullpath))
276{
277 Q_D(KService);
278
279 KDesktopFile config(_fullpath);
280 d->init(&config, this);
281}
282
283KService::KService(const KDesktopFile *config, const QString &entryPath)
284 : KSycocaEntry(*new KServicePrivate(entryPath.isEmpty() ? config->fileName() : entryPath))
285{
286 Q_D(KService);
287
288 d->init(config, this);
289}
290
291KService::KService(QDataStream &_str, int _offset)
292 : KSycocaEntry(*new KServicePrivate(_str, _offset))
293{
294 Q_D(KService);
295 KService::Ptr serviceClone(new KService(*this));
296 for (KServiceAction &action : d->m_actions) {
297 action.setService(serviceClone);
298 }
299}
300
301KService::KService(const KService &other)
302 : KSycocaEntry(*new KServicePrivate(*other.d_func()))
303{
304}
305
306KService::~KService()
307{
308}
309
310bool KService::hasMimeType(const QString &mimeType) const
311{
312 Q_D(const KService);
313 QMimeDatabase db;
314 const QString mime = db.mimeTypeForName(mimeType).name();
315 if (mime.isEmpty()) {
316 return false;
317 }
318 int serviceOffset = offset();
319 if (serviceOffset) {
321 KMimeTypeFactory *factory = KSycocaPrivate::self()->mimeTypeFactory();
322 const int mimeOffset = factory->entryOffset(mime);
323 const int serviceOffersOffset = factory->serviceOffersOffset(mime);
324 if (serviceOffersOffset == -1) {
325 return false;
326 }
327 return KSycocaPrivate::self()->serviceFactory()->hasOffer(mimeOffset, serviceOffersOffset, serviceOffset);
328 }
329
330 return d->m_mimeTypes.contains(mime);
331}
332
334{
335 Q_D(const KService);
336 return d->property(_name, t);
337}
338
339template<>
341{
342 Q_D(const KService);
343
344 if (_name == QLatin1String("Type")) {
345 return d->m_strType;
346 } else if (_name == QLatin1String("Name")) {
347 return d->m_strName;
348 } else if (_name == QLatin1String("Exec")) {
349 return d->m_strExec;
350 } else if (_name == QLatin1String("Icon")) {
351 return d->m_strIcon;
352 } else if (_name == QLatin1String("TerminalOptions")) {
353 return d->m_strTerminalOptions;
354 } else if (_name == QLatin1String("Path")) {
355 return d->m_strWorkingDirectory;
356 } else if (_name == QLatin1String("Comment")) {
357 return d->m_strComment;
358 } else if (_name == QLatin1String("GenericName")) {
359 return d->m_strGenName;
360 } else if (_name == QLatin1String("DesktopEntryPath")) {
361 return d->path;
362 } else if (_name == QLatin1String("DesktopEntryName")) {
363 return d->m_strDesktopEntryName;
364 } else if (_name == QLatin1String("UntranslatedName")) {
365 return d->m_untranslatedName;
366 } else if (_name == QLatin1String("UntranslatedGenericName")) {
367 return d->m_untranslatedGenericName;
368 }
369
370 auto it = d->m_mapProps.constFind(_name);
371
372 if (it != d->m_mapProps.cend()) {
373 return it.value().toString();
374 }
375
376 return QString();
377}
378
379QVariant KServicePrivate::property(const QString &_name, QMetaType::Type t) const
380{
381 if (_name == QLatin1String("Terminal")) {
382 return QVariant(m_bTerminal);
383 } else if (_name == QLatin1String("AllowAsDefault")) {
384 return QVariant(m_bAllowAsDefault);
385 } else if (_name == QLatin1String("Categories")) {
386 return QVariant(categories);
387 } else if (_name == QLatin1String("Keywords")) {
388 return QVariant(m_lstKeywords);
389 } else if (_name == QLatin1String("FormFactors")) {
390 return QVariant(m_lstFormFactors);
391 }
392
393 auto it = m_mapProps.constFind(_name);
394 if (it == m_mapProps.cend() || !it.value().isValid()) {
395 // qCDebug(SERVICES) << "Property not found " << _name;
396 return QVariant(); // No property set.
397 }
398
399 if (it->typeId() == t) {
400 return it.value(); // no conversion necessary
401 } else {
402 // All others
403 // For instance properties defined as StringList, like MimeTypes.
404 // XXX This API is accessible only through a friend declaration.
405 return KConfigGroup::convertToQVariant(_name.toUtf8().constData(), it.value().toString().toUtf8(), QVariant(QMetaType(t)));
406 }
407}
408
410{
412 return KSycocaPrivate::self()->serviceFactory()->allServices();
413}
414
416{
418 return KSycocaPrivate::self()->serviceFactory()->findServiceByDesktopPath(_name);
419}
420
422{
424 return KSycocaPrivate::self()->serviceFactory()->findServiceByDesktopName(_name);
425}
426
428{
430 return KSycocaPrivate::self()->serviceFactory()->findServiceByMenuId(_name);
431}
432
434{
436 return KSycocaPrivate::self()->serviceFactory()->findServiceByStorageId(_storageId);
437}
438
440{
441 return property<bool>(QStringLiteral("X-KDE-SubstituteUID"));
442}
443
445{
446 // See also KDesktopFile::tryExec()
447 QString user = property<QString>(QStringLiteral("X-KDE-Username"));
448 if (user.isEmpty()) {
449 user = QString::fromLocal8Bit(qgetenv("ADMIN_ACCOUNT"));
450 }
451 if (user.isEmpty()) {
452 user = QStringLiteral("root");
453 }
454 return user;
455}
456
458{
459 Q_D(const KService);
460
461 const QString envVar = QString::fromLatin1(qgetenv("XDG_CURRENT_DESKTOP"));
462
464
465 const QString kde = QStringLiteral("KDE");
466 if (currentDesktops.isEmpty()) {
467 // This could be an old display manager, or e.g. a failsafe session with no desktop name
468 // In doubt, let's say we show KDE stuff.
469 currentDesktops.append(kde);
470 }
471
472 // This algorithm is described in the desktop entry spec
473
474 auto it = d->m_mapProps.constFind(QStringLiteral("OnlyShowIn"));
475 if (it != d->m_mapProps.cend()) {
476 const QVariant &val = it.value();
477 if (val.isValid()) {
478 const QStringList aList = val.toString().split(QLatin1Char(';'));
479 return std::any_of(currentDesktops.cbegin(), currentDesktops.cend(), [&aList](const auto desktop) {
480 return aList.contains(desktop);
481 });
482 }
483 }
484
485 it = d->m_mapProps.constFind(QStringLiteral("NotShowIn"));
486 if (it != d->m_mapProps.cend()) {
487 const QVariant &val = it.value();
488 if (val.isValid()) {
489 const QStringList aList = val.toString().split(QLatin1Char(';'));
490 return std::none_of(currentDesktops.cbegin(), currentDesktops.cend(), [&aList](const auto desktop) {
491 return aList.contains(desktop);
492 });
493 }
494 }
495
496 return true;
497}
498
500{
501 Q_D(const KService);
502 const QString platform = QCoreApplication::instance()->property("platformName").toString();
503 if (platform.isEmpty()) {
504 return true;
505 }
506
507 auto it = d->m_mapProps.find(QStringLiteral("X-KDE-OnlyShowOnQtPlatforms"));
508 if ((it != d->m_mapProps.end()) && (it->isValid())) {
509 const QStringList aList = it->toString().split(QLatin1Char(';'));
510 if (!aList.contains(platform)) {
511 return false;
512 }
513 }
514
515 it = d->m_mapProps.find(QStringLiteral("X-KDE-NotShowOnQtPlatforms"));
516 if ((it != d->m_mapProps.end()) && (it->isValid())) {
517 const QStringList aList = it->toString().split(QLatin1Char(';'));
518 if (aList.contains(platform)) {
519 return false;
520 }
521 }
522 return true;
523}
524
526{
527 if (property<bool>(QStringLiteral("NoDisplay"))) {
528 return true;
529 }
530
531 if (!showInCurrentDesktop()) {
532 return true;
533 }
534
535 if (!showOnCurrentPlatform()) {
536 return true;
537 }
538 return false;
539}
540
542{
543 Q_D(const KService);
544 return d->m_untranslatedGenericName;
545}
546
548{
549 Q_D(const KService);
550 return d->m_untranslatedName;
551}
552
554{
555 Q_D(const KService);
556
557 for (const QString &str : {QStringLiteral("X-DocPath"), QStringLiteral("DocPath")}) {
558 auto it = d->m_mapProps.constFind(str);
559 if (it != d->m_mapProps.cend()) {
560 const QVariant variant = it.value();
561 Q_ASSERT(variant.isValid());
562 const QString path = variant.toString();
563 if (!path.isEmpty()) {
564 return path;
565 }
566 }
567 }
568
569 return {};
570}
571
573{
574 Q_D(const KService);
575 // Can we pass multiple files on the command line or do we have to start the application for every single file ?
576 return (d->m_strExec.contains(QLatin1String("%F")) //
577 || d->m_strExec.contains(QLatin1String("%U")) //
578 || d->m_strExec.contains(QLatin1String("%N")) //
579 || d->m_strExec.contains(QLatin1String("%D")));
580}
581
583{
584 Q_D(const KService);
585 return d->categories;
586}
587
589{
590 Q_D(const KService);
591 return d->menuId;
592}
593
594void KService::setMenuId(const QString &_menuId)
595{
596 Q_D(KService);
597 d->menuId = _menuId;
598}
599
601{
602 Q_D(const KService);
603 return d->storageId();
604}
605
606// not sure this is still used anywhere...
608{
609 Q_D(const KService);
610 if (d->menuId.isEmpty() //
611 || entryPath().startsWith(QLatin1String(".hidden")) //
612 || (QDir::isRelativePath(entryPath()) && d->categories.isEmpty())) {
614 }
615
617}
618
619QString KService::newServicePath(bool showInMenu, const QString &suggestedName, QString *menuId, const QStringList *reservedMenuIds)
620{
621 Q_UNUSED(showInMenu); // TODO KDE5: remove argument
622
623 QString base = suggestedName;
624 QString result;
625 for (int i = 1; true; i++) {
626 if (i == 1) {
627 result = base + QStringLiteral(".desktop");
628 } else {
629 result = base + QStringLiteral("-%1.desktop").arg(i);
630 }
631
632 if (reservedMenuIds && reservedMenuIds->contains(result)) {
633 continue;
634 }
635
636 // Lookup service by menu-id
638 if (s) {
639 continue;
640 }
641
642 if (!QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("applications/") + result).isEmpty()) {
643 continue;
644 }
645
646 break;
647 }
648 if (menuId) {
649 *menuId = result;
650 }
651
653}
654
656{
657 Q_D(const KService);
658 return d->m_strType == QLatin1String("Application");
659}
660
662{
663 Q_D(const KService);
664 return d->m_strExec;
665}
666
668{
669 Q_D(const KService);
670 return d->m_strIcon;
671}
672
674{
675 Q_D(const KService);
676 return d->m_strTerminalOptions;
677}
678
680{
681 Q_D(const KService);
682 return d->m_bTerminal;
683}
684
686{
687 QVariant prop = property<bool>(QStringLiteral("PrefersNonDefaultGPU"));
688 if (!prop.isValid()) {
689 // For backwards compatibility
690 prop = property<bool>(QStringLiteral("X-KDE-RunOnDiscreteGpu"));
691 }
692
693 return prop.isValid() && prop.toBool();
694}
695
697{
698 Q_D(const KService);
699 return d->m_strDesktopEntryName;
700}
701
703{
704 Q_D(const KService);
705 return d->m_strWorkingDirectory;
706}
707
709{
710 Q_D(const KService);
711 return d->m_strComment;
712}
713
715{
716 Q_D(const KService);
717 return d->m_strGenName;
718}
719
721{
722 Q_D(const KService);
723 return d->m_lstKeywords;
724}
725
727{
728 Q_D(const KService);
729 QMimeDatabase db;
731
732 for (const auto &mimeName : d->m_mimeTypes) {
733 if (db.mimeTypeForName(mimeName).isValid()) { // keep only mimetypes, filter out servicetypes
734 ret.append(mimeName);
735 }
736 }
737 return ret;
738}
739
741{
742 Q_D(const KService);
743
745
746 const QLatin1String schemeHandlerPrefix("x-scheme-handler/");
747 for (const auto &mimeName : d->m_mimeTypes) {
748 if (mimeName.startsWith(schemeHandlerPrefix)) {
749 ret.append(mimeName.mid(schemeHandlerPrefix.size()));
750 }
751 }
752
753 return ret;
754}
755
757{
758 Q_D(const KService);
759
761
762 ret << schemeHandlers();
763
764 const QStringList protocols = property<QStringList>(QStringLiteral("X-KDE-Protocols"));
765 for (const QString &protocol : protocols) {
766 if (!ret.contains(protocol)) {
767 ret.append(protocol);
768 }
769 }
770
771 return ret;
772}
773
775{
776 Q_D(KService);
777 d->m_bTerminal = b;
778}
779
781{
782 Q_D(KService);
783 d->m_strTerminalOptions = options;
784}
785
786void KService::setExec(const QString &exec)
787{
788 Q_D(KService);
789
790 if (!exec.isEmpty()) {
791 d->m_strExec = exec;
792 d->path.clear();
793 }
794}
795
797{
798 Q_D(KService);
799
800 if (!workingDir.isEmpty()) {
801 d->m_strWorkingDirectory = workingDir;
802 d->path.clear();
803 }
804}
805
807{
808 Q_D(const KService);
809 return d->m_actions;
810}
811
813{
814 return KServiceUtilPrivate::completeBaseName(property<QString>(QStringLiteral("X-KDE-AliasFor")));
815}
816
817void KService::setActions(const QList<KServiceAction> &actions)
818{
819 Q_D(KService);
820 d->m_actions = actions;
821}
822
823std::optional<bool> KService::startupNotify() const
824{
825 Q_D(const KService);
826
827 if (QVariant value = d->m_mapProps.value(QStringLiteral("StartupNotify")); value.isValid()) {
828 return value.toBool();
829 }
830
831 if (QVariant value = d->m_mapProps.value(QStringLiteral("X-KDE-StartupNotify")); value.isValid()) {
832 return value.toBool();
833 }
834
835 return {};
836}
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:582
QStringList mimeTypes() const
Returns the list of MIME types that this application supports.
Definition kservice.cpp:726
static Ptr serviceByStorageId(const QString &_storageId)
Find a application by its storage-id or desktop-file path.
Definition kservice.cpp:433
void setExec(const QString &exec)
Overrides the "Exec=" line of the service.
Definition kservice.cpp:786
void setWorkingDirectory(const QString &workingDir)
Overrides the "Path=" line of the application.
Definition kservice.cpp:796
QString storageId() const
Returns a normalized ID suitable for storing in configuration files.
Definition kservice.cpp:600
QString desktopEntryName() const
Returns the filename of the desktop entry without any extension, e.g.
Definition kservice.cpp:696
QStringList keywords() const
Returns a list of descriptive keywords for the application, if there are any.
Definition kservice.cpp:720
void setTerminalOptions(const QString &options)
Definition kservice.cpp:780
QList< KServiceAction > actions() const
Returns the actions defined in this desktop file.
Definition kservice.cpp:806
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:619
bool allowMultipleFiles() const
Checks whether this application can handle several files as startup arguments.
Definition kservice.cpp:572
QStringList supportedProtocols() const
Returns the list of protocols this application supports.
Definition kservice.cpp:756
QString genericName() const
Returns the generic name for the application, if there is one (e.g.
Definition kservice.cpp:714
bool substituteUid() const
Checks whether the application needs to run under a different UID.
Definition kservice.cpp:439
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:679
QString terminalOptions() const
Returns any options associated with the terminal the application runs in, if it requires a terminal.
Definition kservice.cpp:673
static List allServices()
Returns the whole list of applications.
Definition kservice.cpp:409
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:262
bool noDisplay() const
Whether the entry should be hidden from the menu.
Definition kservice.cpp:525
QString username() const
Returns the user name if the application runs with a different user id.
Definition kservice.cpp:444
QString aliasFor() const
A desktop file name that this application is an alias for.
Definition kservice.cpp:812
QString locateLocal() const
Returns a path that can be used for saving changes to this application.
Definition kservice.cpp:607
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:421
QString menuId() const
Returns the menu ID of the application desktop entry.
Definition kservice.cpp:588
bool showOnCurrentPlatform() const
Whether the application should be shown on the current platform (e.g.
Definition kservice.cpp:499
QString exec() const
Returns the executable.
Definition kservice.cpp:661
void setTerminal(bool b)
Definition kservice.cpp:774
QString comment() const
Returns the descriptive comment for the application, if there is one.
Definition kservice.cpp:708
QString untranslatedGenericName() const
Returns the untranslated (US English) generic name for the application, if there is one (e....
Definition kservice.cpp:541
QString untranslatedName() const
Definition kservice.cpp:547
QString icon() const
Returns the name of the icon.
Definition kservice.cpp:667
QStringList schemeHandlers() const
Returns the list of scheme handlers this application supports.
Definition kservice.cpp:740
void setMenuId(const QString &menuId)
Definition kservice.cpp:594
QString workingDirectory() const
Definition kservice.cpp:702
QString docPath() const
The path to the documentation for this application.
Definition kservice.cpp:553
std::optional< bool > startupNotify() const
Returns the value of StartupNotify for this service.
Definition kservice.cpp:823
static Ptr serviceByMenuId(const QString &_menuId)
Find a application by its menu-id.
Definition kservice.cpp:427
bool showInCurrentDesktop() const
Whether the application should be shown in the current desktop (including in context menus).
Definition kservice.cpp:457
bool isApplication() const
Whether this service is an application.
Definition kservice.cpp:655
static Ptr serviceByDesktopPath(const QString &_path)
Find a application based on its path as returned by entryPath().
Definition kservice.cpp:415
bool hasMimeType(const QString &mimeType) const
Checks whether the application supports this MIME type.
Definition kservice.cpp:310
bool runOnDiscreteGpu() const
Returns true if the application indicates that it's preferred to run on a discrete graphics card,...
Definition kservice.cpp:685
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)
bool isEmpty() const const
QMap::const_iterator constBegin() const const
QMap::const_iterator constEnd() const const
QMap::const_key_value_iterator constKeyValueBegin() const const
QMap::const_key_value_iterator constKeyValueEnd() const const
bool contains(const Key &key) const const
QMap::iterator insert(const Key &key, const T &value)
int 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(QStandardPaths::StandardLocation type)
QString locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
QString writableLocation(QStandardPaths::StandardLocation type)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
void clear()
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString fromLatin1(const char *str, int size)
QString fromLocal8Bit(const char *str, int size)
QString & insert(int position, QChar ch)
bool isEmpty() const const
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QByteArray toUtf8() const const
SkipEmptyParts
QVariant fromValue(const T &value)
bool isValid() const const
QString toString() const const
T value() const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:43:03 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.