File indexing completed on 2023-11-26 10:45:34

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 1998, 1999 Torben Weis <weis@kde.org>
0004     SPDX-FileCopyrightText: 1999-2006 David Faure <faure@kde.org>
0005     SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #ifndef KSERVICE_H
0011 #define KSERVICE_H
0012 
0013 #include "kserviceaction.h"
0014 #include <QCoreApplication>
0015 #include <QStringList>
0016 #include <QVariant>
0017 #include <kserviceconversioncheck_p.h>
0018 #include <ksycocaentry.h>
0019 
0020 #include <optional>
0021 
0022 class QDataStream;
0023 class KDesktopFile;
0024 class QWidget;
0025 
0026 class KServicePrivate;
0027 
0028 /**
0029  * @class KService kservice.h <KService>
0030  *
0031  * Represents an installed application.
0032  *
0033  * To obtain a KService instance for a specific application you typically use serviceByDesktopName(), e.g.:
0034  *
0035  * @code
0036  * KService::Ptr service = KService::serviceByDesktopName("org.kde.kate");
0037  * @endcode
0038  *
0039  * Other typical usage would be in combination with KApplicationTrader to obtain e.g. the default application for a given file type.
0040  *
0041  * @see <a href="https://specifications.freedesktop.org/desktop-entry-spec/latest/">Desktop Entry Specification</a>
0042  */
0043 class KSERVICE_EXPORT KService : public KSycocaEntry
0044 {
0045 public:
0046     /**
0047      * A shared data pointer for KService.
0048      */
0049     typedef QExplicitlySharedDataPointer<KService> Ptr;
0050     /**
0051      * A list of shared data pointers for KService.
0052      */
0053     typedef QList<Ptr> List;
0054 
0055     /**
0056      * Construct a temporary service with a given name, exec-line and icon.
0057      * @param name the name of the service
0058      * @param exec the executable
0059      * @param icon the name of the icon
0060      */
0061     KService(const QString &name, const QString &exec, const QString &icon);
0062 
0063     /**
0064      * Construct a service and take all information from a .desktop file.
0065      *
0066      * @param fullpath Full path to the .desktop file.
0067      */
0068     explicit KService(const QString &fullpath);
0069 
0070     /**
0071      * Construct a service and take all information from a desktop file.
0072      * @param config the desktop file to read
0073      * @param optional relative path to store for findByName
0074      */
0075     explicit KService(const KDesktopFile *config, const QString &entryPath = QString());
0076 
0077     KService(const KService &other);
0078 
0079     ~KService() override;
0080 
0081     /**
0082      * Whether this service is an application
0083      * @return true if this service is an application, i.e. it has Type=Application in its
0084      * .desktop file and exec() will not be empty.
0085      */
0086     bool isApplication() const;
0087 
0088     /**
0089      * Returns the executable.
0090      * @return the command that the service executes,
0091      *         or QString() if not set
0092      */
0093     QString exec() const;
0094 
0095     /**
0096      * Returns the name of the icon.
0097      * @return the icon associated with the service,
0098      *         or QString() if not set
0099      */
0100     QString icon() const;
0101     /**
0102      * Checks whether the application should be run in a terminal.
0103      *
0104      * This corresponds to `Terminal=true` in the .desktop file.
0105      *
0106      * @return @c true if the application should be run in a terminal.
0107      */
0108     bool terminal() const;
0109 
0110     /**
0111      * Returns any options associated with the terminal the application
0112      * runs in, if it requires a terminal.
0113      *
0114      * The application must be a TTY-oriented program.
0115      * @return the terminal options,
0116      *         or QString() if not set
0117      */
0118     QString terminalOptions() const;
0119 
0120     /**
0121      * Returns @c true if the application indicates that it's preferred to run
0122      * on a discrete graphics card, otherwise return @c false.
0123      *
0124      * In releases older than 5.86, this method checked for the @c X-KDE-RunOnDiscreteGpu
0125      * key in the .desktop file represented by this service; starting from 5.86 this method
0126      * now also checks for @c PrefersNonDefaultGPU key (added to the Freedesktop.org desktop
0127      * entry spec in version 1.4 of the spec).
0128      *
0129      * @since 5.30
0130      */
0131     bool runOnDiscreteGpu() const;
0132 
0133     /**
0134      * @brief Checks whether the application needs to run under a different UID.
0135      * @return @c true if the application needs to run under a different UID.
0136      * @see username()
0137      */
0138     bool substituteUid() const;
0139     /**
0140      * Returns the user name if the application runs with a
0141      * different user id.
0142      * @return the username under which the service has to be run,
0143      *         or QString() if not set
0144      * @see substituteUid()
0145      */
0146     QString username() const;
0147 
0148     /**
0149      * Returns the filename of the desktop entry without any
0150      * extension, e.g. "org.kde.kate"
0151      * @return the name of the desktop entry without path or extension,
0152      *         or QString() if not set
0153      */
0154     QString desktopEntryName() const;
0155 
0156     /**
0157      * Returns the menu ID of the application desktop entry.
0158      * The menu ID is used to add or remove the entry to a menu.
0159      * @return the menu ID
0160      */
0161     QString menuId() const;
0162 
0163     /**
0164      * Returns a normalized ID suitable for storing in configuration files.
0165      * It will be based on the menu-id when available and otherwise falls
0166      * back to entryPath()
0167      * @return the storage ID
0168      */
0169     QString storageId() const;
0170 
0171     /**
0172      * @return the working directory to run the program in,
0173      *         or QString() if not set
0174      * @since 5.63
0175      */
0176     QString workingDirectory() const;
0177 
0178     /**
0179      * Returns the descriptive comment for the application, if there is one.
0180      * @return the descriptive comment for the application, or QString()
0181      *         if not set
0182      */
0183     QString comment() const;
0184 
0185     /**
0186      * Returns the generic name for the application, if there is one
0187      * (e.g. "Mail Client").
0188      * @return the generic name,
0189      *         or QString() if not set
0190      */
0191     QString genericName() const;
0192 
0193     /**
0194      * Returns the untranslated (US English) generic name
0195      * for the application, if there is one
0196      * (e.g. "Mail Client").
0197      * @return the generic name,
0198      *         or QString() if not set
0199      */
0200     QString untranslatedGenericName() const;
0201 
0202     /**
0203      * @return untranslated name for the given service
0204      *
0205      * @since 6.0
0206      */
0207     QString untranslatedName() const;
0208     /**
0209      * Returns a list of descriptive keywords for the application, if there are any.
0210      * @return the list of keywords
0211      */
0212     QStringList keywords() const;
0213 
0214     /**
0215      * Returns a list of VFolder categories.
0216      * @return the list of VFolder categories
0217      */
0218     QStringList categories() const;
0219 
0220     /**
0221      * Returns the list of MIME types that this application supports.
0222      * Note that this doesn't include inherited MIME types,
0223      * only the MIME types listed in the .desktop file.
0224      * @since 4.8.3
0225      */
0226     QStringList mimeTypes() const;
0227 
0228     /**
0229      * Returns the list of protocols this application supports.
0230      *
0231      * This is taken from the x-scheme-handler MIME types
0232      * listed in the .destkop file as well as the 'X-KDE-Protocols'
0233      * entry
0234      *
0235      * For example a web browser could return {"http", "https"}.
0236      * @since 6.0
0237      */
0238     QStringList supportedProtocols() const;
0239 
0240     /**
0241      * Checks whether the application supports this MIME type
0242      * @param mimeType The name of the MIME type you are
0243      *        interested in determining whether this service supports.
0244      * @since 4.6
0245      */
0246     bool hasMimeType(const QString &mimeType) const;
0247 
0248     /**
0249      * Returns the actions defined in this desktop file
0250      */
0251     QList<KServiceAction> actions() const;
0252 
0253     /**
0254      * Checks whether this application can handle several files as
0255      * startup arguments.
0256      * @return true if multiple files may be passed to this service at
0257      * startup. False if only one file at a time may be passed.
0258      */
0259     bool allowMultipleFiles() const;
0260 
0261     /**
0262      * What preference to associate with this application initially (before
0263      * the user has had any chance to define a profile for it).
0264      * The bigger the value, the stronger the preference for the application.
0265      * @return the service preference level of the application
0266      */
0267     int initialPreference() const;
0268 
0269     /**
0270      * Whether the entry should be hidden from the menu.
0271      * @return @c true to hide this application from the menu
0272      *
0273      * Such services still appear in trader queries, i.e. in
0274      * "Open With" popup menus for instance.
0275      */
0276     bool noDisplay() const;
0277 
0278     /**
0279      * Whether the application should be shown in the current desktop
0280      * (including in context menus).
0281      * @return true if the application should be shown in the current desktop.
0282      *
0283      * KApplicationTrader honors this and removes such services
0284      * from its results.
0285      *
0286      * @since 5.0
0287      */
0288     bool showInCurrentDesktop() const;
0289 
0290     /**
0291      * Whether the application should be shown on the current
0292      * platform (e.g. on xcb or on wayland).
0293      * @return @c true if the application should be shown on the current platform.
0294      *
0295      * @since 5.0
0296      */
0297     bool showOnCurrentPlatform() const;
0298 
0299     /**
0300      * The path to the documentation for this application.
0301      * @since 4.2
0302      * @return the documentation path, or QString() if not set
0303      */
0304     QString docPath() const;
0305 
0306     /**
0307      * Returns the requested property.
0308      *
0309      * @param _name the name of the property
0310      * @param t the assumed type of the property
0311      * @return the property, or invalid if not found
0312      *
0313      * @since 5.102
0314      */
0315     QVariant property(const QString &_name, QMetaType::Type t) const;
0316 
0317     /**
0318      * Returns the requested property.
0319      *
0320      * @tparam T the type of the requested property.
0321      *
0322      * @param name the name of the property.
0323      *
0324      * @since 6.0
0325      */
0326     template<typename T>
0327     T property(const QString &name) const
0328     {
0329         KServiceConversionCheck::to_QVariant<T>();
0330         return property(name, static_cast<QMetaType::Type>(qMetaTypeId<T>())).value<T>();
0331     }
0332 
0333     /**
0334      * Returns a path that can be used for saving changes to this
0335      * application
0336      * @return path that can be used for saving changes to this application
0337      */
0338     QString locateLocal() const;
0339 
0340     /**
0341      * @internal
0342      * Set the menu id
0343      */
0344     void setMenuId(const QString &menuId);
0345     /**
0346      * @internal
0347      * Sets whether to use a terminal or not
0348      */
0349     void setTerminal(bool b);
0350     /**
0351      * @internal
0352      * Sets the terminal options to use
0353      */
0354     void setTerminalOptions(const QString &options);
0355 
0356     /**
0357      * Overrides the "Exec=" line of the service.
0358      *
0359      * If @ref exec is not empty, its value will override the one
0360      * the one set when this application was created.
0361      *
0362      * Please note that @ref entryPath is also cleared so the application
0363      * will no longer be associated with a specific config file.
0364      *
0365      * @internal
0366      * @since 4.11
0367      */
0368     void setExec(const QString &exec);
0369 
0370     /**
0371      * Overrides the "Path=" line of the application.
0372      *
0373      * If @ref workingDir is not empty, its value will override
0374      * the one set when this application was created.
0375      *
0376      * Please note that @ref entryPath is also cleared so the application
0377      * will no longer be associated with a specific config file.
0378      *
0379      * @internal
0380      * @param workingDir
0381      * @since 5.79
0382      */
0383     void setWorkingDirectory(const QString &workingDir);
0384 
0385     /**
0386      * Find a application based on its path as returned by entryPath().
0387      * It's usually better to use serviceByStorageId() instead.
0388      *
0389      * @param _path the path of the configuration file
0390      * @return a pointer to the requested application or @c nullptr if the application is
0391      *         unknown.
0392      * @em Very @em important: Don't store the result in a KService* !
0393      */
0394     static Ptr serviceByDesktopPath(const QString &_path);
0395 
0396     /**
0397      * Find an application by the name of its desktop file, not depending on
0398      * its actual location (as long as it's under the applications or application
0399      * directories). For instance "konqbrowser" or "kcookiejar". Note that
0400      * the ".desktop" extension is implicit.
0401      *
0402      * This is the recommended method (safe even if the user moves stuff)
0403      * but note that it assumes that no two entries have the same filename.
0404      *
0405      * @param _name the name of the configuration file
0406      * @return a pointer to the requested application or @c nullptr if the application is
0407      *         unknown.
0408      * @em Very @em important: Don't store the result in a KService* !
0409      */
0410     static Ptr serviceByDesktopName(const QString &_name);
0411 
0412     /**
0413      * Find a application by its menu-id
0414      *
0415      * @param _menuId the menu id of the application
0416      * @return a pointer to the requested application or @c nullptr if the application is
0417      *         unknown.
0418      * @em Very @em important: Don't store the result in a KService* !
0419      */
0420     static Ptr serviceByMenuId(const QString &_menuId);
0421 
0422     /**
0423      * Find a application by its storage-id or desktop-file path. This
0424      * function will try very hard to find a matching application.
0425      *
0426      * @param _storageId the storage id or desktop-file path of the application
0427      * @return a pointer to the requested application or @c nullptr if the application is
0428      *         unknown.
0429      * @em Very @em important: Don't store the result in a KService* !
0430      */
0431     static Ptr serviceByStorageId(const QString &_storageId);
0432 
0433     /**
0434      * Returns the whole list of applications.
0435      *
0436      *  Useful for being able to
0437      * to display them in a list box, for example.
0438      * More memory consuming than the ones above, don't use unless
0439      * really necessary.
0440      * @return the list of all applications
0441      */
0442     static List allServices();
0443 
0444     /**
0445      * Returns a path that can be used to create a new KService based
0446      * on @p suggestedName.
0447      * @param showInMenu @c true, if the application should be shown in the KDE menu
0448      *        @c false, if the application should be hidden from the menu
0449      *        This argument isn't used anymore, use `NoDisplay=true` to hide the application.
0450      * @param suggestedName name to base the file on, if an application with such a
0451      *        name already exists, a suffix will be added to make it unique
0452      *        (e.g. foo.desktop, foo-1.desktop, foo-2.desktop).
0453      * @param menuId If provided, menuId will be set to the menu id to use for
0454      *        the KService
0455      * @param reservedMenuIds If provided, the path and menu id will be chosen
0456      *        in such a way that the new menu id does not conflict with any
0457      *        of the reservedMenuIds
0458      * @return The path to use for the new KService.
0459      */
0460     static QString newServicePath(bool showInMenu, const QString &suggestedName, QString *menuId = nullptr, const QStringList *reservedMenuIds = nullptr);
0461 
0462     /**
0463      * @brief A desktop file name that this application is an alias for.
0464      *
0465      * This is used when a `NoDisplay` application is used to enforce specific handling
0466      * for an application. In that case the `NoDisplay` application is an `AliasFor` another
0467      * application and be considered roughly equal to the `AliasFor` application (which should
0468      * not be `NoDisplay=true`)
0469      * For example Okular supplies a desktop file for each supported format (e.g. PDF), all
0470      * of which `NoDisplay` and it is merely there to selectively support specific file formats.
0471      * A UI may choose to display the aliased entry org.kde.okular instead of the NoDisplay entries.
0472      *
0473      * @since 5.96
0474      *
0475      * @return QString desktopName of the aliased application (excluding .desktop suffix)
0476      */
0477     QString aliasFor() const;
0478 
0479     /**
0480      * Returns the value of StartupNotify for this service.
0481      *
0482      * If the service doesn't define a value nullopt is returned.
0483      *
0484      * See StartupNotify in the <a href="https://specifications.freedesktop.org/desktop-entry-spec/latest/">Desktop Entry Specification</a>.
0485      *
0486      * @since 6.0
0487      */
0488     std::optional<bool> startupNotify() const;
0489 
0490 private:
0491     friend class KBuildServiceFactory;
0492 
0493     /// @internal for KBuildSycoca only
0494     struct KSERVICE_NO_EXPORT ServiceTypeAndPreference {
0495         ServiceTypeAndPreference()
0496             : preference(-1)
0497             , serviceType()
0498         {
0499         }
0500         ServiceTypeAndPreference(int pref, const QString &servType)
0501             : preference(pref)
0502             , serviceType(servType)
0503         {
0504         }
0505         int preference;
0506         QString serviceType; // or MIME type
0507     };
0508     /// @internal for KBuildSycoca only
0509     QVector<ServiceTypeAndPreference> _k_accessServiceTypes();
0510 
0511     void setActions(const QList<KServiceAction> &actions);
0512 
0513     friend QDataStream &operator>>(QDataStream &, ServiceTypeAndPreference &);
0514     friend QDataStream &operator<<(QDataStream &, const ServiceTypeAndPreference &);
0515 
0516     Q_DECLARE_PRIVATE(KService)
0517 
0518     friend class KServiceFactory;
0519 
0520     /**
0521      * @internal
0522      * Construct a service from a stream.
0523      * The stream must already be positioned at the correct offset.
0524      */
0525     KSERVICE_NO_EXPORT KService(QDataStream &str, int offset);
0526 };
0527 #endif