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

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