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 | |
22 | class QDataStream; |
23 | class KDesktopFile; |
24 | class QWidget; |
25 | |
26 | class 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 | */ |
43 | class KSERVICE_EXPORT KService : public KSycocaEntry |
44 | { |
45 | public: |
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 () 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 () 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 (const QString &); |
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 (const QString &); |
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 , const QString &suggestedName, QString * = nullptr, const QStringList * = 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 | |
484 | private: |
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 | |
503 | template<> |
504 | KSERVICE_EXPORT QString KService::property<QString>(const QString &name) const; |
505 | |
506 | #endif |
507 | |