1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 1998, 1999 Torben Weis <weis@kde.org>
4 SPDX-FileCopyrightText: 1999-2006 David Faure <faure@kde.org>
5 SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#ifndef KSERVICE_H
11#define KSERVICE_H
12
13#include "kserviceaction.h"
14#include <QCoreApplication>
15#include <QStringList>
16#include <QVariant>
17#include <kserviceconversioncheck_p.h>
18#include <ksycocaentry.h>
19
20#include <optional>
21
22class QDataStream;
23class KDesktopFile;
24class QWidget;
25
26class KServicePrivate;
27
28/*!
29 * \class KService
30 * \inmodule KService
31 *
32 * \brief Represents an installed application.
33 *
34 * To obtain a KService instance for a specific application you typically use serviceByDesktopName(), e.g.:
35 *
36 * \code
37 * KService::Ptr service = KService::serviceByDesktopName("org.kde.kate");
38 * \endcode
39 *
40 * Other typical usage would be in combination with KApplicationTrader to obtain e.g. the default application for a given file type.
41 *
42 * See the \l {https://specifications.freedesktop.org/desktop-entry-spec/latest/} {Desktop Entry Specification}
43 */
44class KSERVICE_EXPORT KService : public KSycocaEntry
45{
46public:
47 /*!
48 * A shared data pointer for KService.
49 */
50 typedef QExplicitlySharedDataPointer<KService> Ptr;
51 /*!
52 * A list of shared data pointers for KService.
53 */
54 typedef QList<Ptr> List;
55
56 /*!
57 * Construct a temporary service with a given name, exec-line and icon.
58 *
59 * \a name the name of the service
60 *
61 * \a exec the executable
62 *
63 * \a icon the name of the icon
64 */
65 KService(const QString &name, const QString &exec, const QString &icon);
66
67 /*!
68 * Construct a service and take all information from a .desktop file.
69 *
70 * \a fullpath Full path to the .desktop file.
71 */
72 explicit KService(const QString &fullpath);
73
74 /*!
75 * Construct a service and take all information from a desktop file.
76 *
77 * \a config the desktop file to read
78 *
79 * \a entryPath optional relative path to store for findByName
80 */
81 explicit KService(const KDesktopFile *config, const QString &entryPath = QString());
82
83 KService(const KService &other);
84
85 ~KService() override;
86
87 /*!
88 * Whether this service is an application
89 *
90 * Returns \c true if this service is an application, i.e. it has \c Type=Application in its
91 * .desktop file and exec() will not be empty.
92 */
93 bool isApplication() const;
94
95 /*!
96 * Returns the command that the service executes,
97 * or QString() if not set
98 */
99 QString exec() const;
100
101 /*!
102 * Returns the name of the icon associated with the service,
103 * or QString() if not set
104 */
105 QString icon() const;
106 /*!
107 * Checks whether the application should be run in a terminal.
108 *
109 * This corresponds to \c Terminal=true in the .desktop file.
110 *
111 * Returns \c true if the application should be run in a terminal.
112 */
113 bool terminal() const;
114
115 /*!
116 * Returns any options associated with the terminal the application
117 * runs in, if it requires a terminal.
118 *
119 * The application must be a TTY-oriented program.
120 */
121 QString terminalOptions() const;
122
123 /*!
124 * Returns \c true if the application indicates that it's preferred to run
125 * on a discrete graphics card, otherwise return \c false.
126 *
127 * In releases older than 5.86, this method checked for the \c X-KDE-RunOnDiscreteGpu
128 * key in the .desktop file represented by this service; starting from 5.86 this method
129 * now also checks for \c PrefersNonDefaultGPU key (added to the Freedesktop.org desktop
130 * entry spec in version 1.4 of the spec).
131 *
132 * \since KService 5.30
133 */
134 bool runOnDiscreteGpu() const;
135
136 /*!
137 * Returns whether the application needs to run under a different UID.
138 * \sa username()
139 */
140 bool substituteUid() const;
141 /*!
142 * Returns the user name if the application runs with a
143 * different user id.
144 * \sa substituteUid()
145 */
146 QString username() const;
147
148 /*!
149 * Returns the filename of the desktop entry without any
150 * extension, e.g. "org.kde.kate"
151 */
152 QString desktopEntryName() const;
153
154 /*!
155 * Returns the menu ID of the application desktop entry.
156 *
157 * The menu ID is used to add or remove the entry to a menu.
158 */
159 QString menuId() const;
160
161 /*!
162 * Returns a normalized ID suitable for storing in configuration files.
163 *
164 * It will be based on the menu-id when available and otherwise falls
165 * back to entryPath()
166 */
167 QString storageId() const;
168
169 /*!
170 * Returns the working directory to run the program in,
171 * or QString() if not set
172 * \since 5.63
173 */
174 QString workingDirectory() const;
175
176 /*!
177 * Returns the descriptive comment for the application, if there is one.
178 * if not set
179 */
180 QString comment() const;
181
182 /*!
183 * Returns the generic name for the application, if there is one
184 * (e.g. "Mail Client").
185 */
186 QString genericName() const;
187
188 /*!
189 * Returns the untranslated (US English) generic name
190 * for the application, if there is one
191 * (e.g. "Mail Client").
192 */
193 QString untranslatedGenericName() const;
194
195 /*!
196 * Returns the untranslated name for the given service
197 *
198 * \since 6.0
199 */
200 QString untranslatedName() const;
201 /*!
202 * Returns a list of descriptive keywords for the application, if there are any.
203 */
204 QStringList keywords() const;
205
206 /*!
207 * Returns a list of VFolder categories.
208 */
209 QStringList categories() const;
210
211 /*!
212 * Returns the list of MIME types that this application supports.
213 *
214 * Note that this doesn't include inherited MIME types,
215 * only the MIME types listed in the .desktop file.
216 *
217 * \since 4.8.3
218 */
219 QStringList mimeTypes() const;
220
221 /*!
222 * Returns the list of scheme handlers this application supports.
223 *
224 * For example a web browser could return {"http", "https"}.
225 *
226 * This is taken from the x-scheme-handler MIME types
227 * listed in the .desktop file.
228 *
229 * \since 6.0
230 */
231 QStringList schemeHandlers() const;
232
233 /*!
234 * Returns the list of protocols this application supports.
235 *
236 * This is taken from the x-scheme-handler MIME types
237 * listed in the .desktop file as well as the 'X-KDE-Protocols'
238 * entry
239 *
240 * For example a web browser could return {"http", "https"}.
241 *
242 * \since 6.0
243 */
244 QStringList supportedProtocols() const;
245
246 /*!
247 * Returns whether the application supports this MIME type
248 *
249 * \a mimeType The name of the MIME type you are
250 * interested in determining whether this service supports.
251 *
252 * \since 4.6
253 */
254 bool hasMimeType(const QString &mimeType) const;
255
256 /*!
257 * Returns the actions defined in this desktop file
258 *
259 * Only valid actions according to specification are included.
260 *
261 * \note This function copies the action list.
262 */
263 QList<KServiceAction> actions() const;
264
265 /*!
266 * Returns whether this application can handle several files as
267 * startup arguments.
268 */
269 bool allowMultipleFiles() const;
270
271 /*!
272 * Returns whether the entry should be hidden from the menu.
273 *
274 * Such services still appear in trader queries, i.e. in
275 * "Open With" popup menus for instance.
276 */
277 bool noDisplay() const;
278
279 /*!
280 * Returns whether the application should be shown in the current desktop
281 * (including in context menus).
282 *
283 * KApplicationTrader honors this and removes such services
284 * from its results.
285 *
286 * \since 5.0
287 */
288 bool showInCurrentDesktop() const;
289
290 /*!
291 * Returns whether the application should be shown on the current
292 * platform (e.g. on xcb or on wayland).
293 *
294 * \since 5.0
295 */
296 bool showOnCurrentPlatform() const;
297
298 /*!
299 * Returns the path to the documentation for this application.
300 *
301 * \since 4.2
302 */
303 QString docPath() const;
304
305 /*!
306 * Returns the requested property.
307 *
308 * T the type of the requested property.
309 *
310 * \a name the name of the property.
311 *
312 * \since 6.0
313 */
314 template<typename T>
315 T property(const QString &name) const
316 {
317 KServiceConversionCheck::to_QVariant<T>();
318 return property(name: name, t: static_cast<QMetaType::Type>(qMetaTypeId<T>())).value<T>();
319 }
320
321 /*!
322 * Returns a path that can be used for saving changes to this
323 * application
324 */
325 QString locateLocal() const;
326
327 /*!
328 * \internal
329 * Set the menu id
330 */
331 void setMenuId(const QString &menuId);
332 /*!
333 * \internal
334 * Sets whether to use a terminal or not
335 */
336 void setTerminal(bool b);
337 /*!
338 * \internal
339 * Sets the terminal options to use
340 */
341 void setTerminalOptions(const QString &options);
342
343 /*!
344 * Overrides the "Exec=" line of the service.
345 *
346 * If \a exec is not empty, its value will override the one
347 * the one set when this application was created.
348 *
349 * Please note that entryPath is also cleared so the application
350 * will no longer be associated with a specific config file.
351 *
352 * \internal
353 * \since 4.11
354 */
355 void setExec(const QString &exec);
356
357 /*!
358 * Overrides the "Path=" line of the application.
359 *
360 * If \a workingDir is not empty, its value will override
361 * the one set when this application was created.
362 *
363 * Please note that entryPath is also cleared so the application
364 * will no longer be associated with a specific config file.
365 *
366 * \internal
367 * \since 5.79
368 */
369 void setWorkingDirectory(const QString &workingDir);
370
371 /*!
372 * Find a application based on its path as returned by entryPath().
373 *
374 * It's usually better to use serviceByStorageId() instead.
375 *
376 * \a _path the path of the configuration file
377 *
378 * Returns a pointer to the requested application or \c nullptr if the application is
379 * unknown.
380 *
381 * Very important: Don't store the result in a KService* !
382 */
383 static Ptr serviceByDesktopPath(const QString &_path);
384
385 /*!
386 * Find an application by the name of its desktop file, not depending on
387 * its actual location (as long as it's under the applications or application
388 * directories). For instance "konqbrowser" or "kcookiejar". Note that
389 * the ".desktop" extension is implicit.
390 *
391 * This is the recommended method (safe even if the user moves stuff)
392 * but note that it assumes that no two entries have the same filename.
393 *
394 * \a _name the name of the configuration file
395 *
396 * Returns a pointer to the requested application or \c nullptr if the application is
397 * unknown.
398 *
399 * Very important: Don't store the result in a KService* !
400 */
401 static Ptr serviceByDesktopName(const QString &_name);
402
403 /*!
404 * Find a application by its menu-id
405 *
406 * \a _menuId the menu id of the application
407 *
408 * Returns a pointer to the requested application or \c nullptr if the application is
409 * unknown.
410 *
411 * Very important: Don't store the result in a KService* !
412 */
413 static Ptr serviceByMenuId(const QString &_menuId);
414
415 /*!
416 * Find a application by its storage-id or desktop-file path. This
417 * function will try very hard to find a matching application.
418 *
419 * \a _storageId the storage id or desktop-file path of the application
420 *
421 * Returns a pointer to the requested application or \c nullptr if the application is
422 * unknown.
423 *
424 * Very important: Don't store the result in a KService* !
425 */
426 static Ptr serviceByStorageId(const QString &_storageId);
427
428 /*!
429 * Returns the whole list of applications.
430 *
431 * Useful for being able to
432 * to display them in a list box, for example.
433 *
434 * More memory consuming than the ones above, don't use unless
435 * really necessary.
436 */
437 static List allServices();
438
439 /*!
440 * Returns a path that can be used to create a new KService based
441 * on \a suggestedName.
442 *
443 * \a showInMenu \c true, if the application should be shown in the KDE menu
444 * \c false, if the application should be hidden from the menu
445 * This argument isn't used anymore, use \c NoDisplay=true to hide the application.
446 *
447 * \a suggestedName name to base the file on, if an application with such a
448 * name already exists, a suffix will be added to make it unique
449 * (e.g. foo.desktop, foo-1.desktop, foo-2.desktop).
450 *
451 * \a menuId If provided, menuId will be set to the menu id to use for
452 * the KService
453 *
454 * \a reservedMenuIds If provided, the path and menu id will be chosen
455 * in such a way that the new menu id does not conflict with any
456 * of the reservedMenuIds
457 */
458 static QString newServicePath(bool showInMenu, const QString &suggestedName, QString *menuId = nullptr, const QStringList *reservedMenuIds = nullptr);
459
460 /*!
461 * A desktop file name that this application is an alias for.
462 *
463 * This is used when a \c NoDisplay application is used to enforce specific handling
464 * for an application. In that case the \c NoDisplay application is an \c AliasFor another
465 * application and be considered roughly equal to the \c AliasFor application (which should
466 * not be \c NoDisplay=true)
467 *
468 * For example Okular supplies a desktop file for each supported format (e.g. PDF), all
469 * of which \c NoDisplay and it is merely there to selectively support specific file formats.
470 * A UI may choose to display the aliased entry org.kde.okular instead of the NoDisplay entries.
471 *
472 * Returns QString desktopName of the aliased application (excluding .desktop suffix)
473 *
474 * \since 5.96
475 */
476 QString aliasFor() const;
477
478 /*!
479 * Returns the value of StartupNotify for this service.
480 *
481 * If the service doesn't define a value nullopt is returned.
482 *
483 * See StartupNotify in the \l {https://specifications.freedesktop.org/desktop-entry-spec/latest/} {Desktop Entry Specification}.
484 *
485 * \since 6.0
486 */
487 std::optional<bool> startupNotify() const;
488
489private:
490 friend class KBuildServiceFactory;
491
492 QVariant property(const QString &_name, QMetaType::Type t) const;
493
494 void setActions(const QList<KServiceAction> &actions);
495
496 Q_DECLARE_PRIVATE(KService)
497
498 friend class KServiceFactory;
499
500 /*!
501 * \internal
502 * Construct a service from a stream.
503 * The stream must already be positioned at the correct offset.
504 */
505 KSERVICE_NO_EXPORT KService(QDataStream &str, int offset);
506};
507
508template<>
509KSERVICE_EXPORT QString KService::property<QString>(const QString &name) const;
510
511#endif
512

source code of kservice/src/services/kservice.h