File indexing completed on 2024-12-08 06:41:29

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 scheme handlers this application supports.
0230      *
0231      * For example a web browser could return {"http", "https"}.
0232      *
0233      * This is taken from the x-scheme-handler MIME types
0234      * listed in the .desktop file.
0235      *
0236      * @since 6.0
0237      *
0238      */
0239     QStringList schemeHandlers() const;
0240 
0241     /**
0242      * Returns the list of protocols this application supports.
0243      *
0244      * This is taken from the x-scheme-handler MIME types
0245      * listed in the .desktop file as well as the 'X-KDE-Protocols'
0246      * entry
0247      *
0248      * For example a web browser could return {"http", "https"}.
0249      * @since 6.0
0250      */
0251     QStringList supportedProtocols() const;
0252 
0253     /**
0254      * Checks whether the application supports this MIME type
0255      * @param mimeType The name of the MIME type you are
0256      *        interested in determining whether this service supports.
0257      * @since 4.6
0258      */
0259     bool hasMimeType(const QString &mimeType) const;
0260 
0261     /**
0262      * Returns the actions defined in this desktop file
0263      */
0264     QList<KServiceAction> actions() const;
0265 
0266     /**
0267      * Checks whether this application can handle several files as
0268      * startup arguments.
0269      * @return true if multiple files may be passed to this service at
0270      * startup. False if only one file at a time may be passed.
0271      */
0272     bool allowMultipleFiles() const;
0273 
0274     /**
0275      * What preference to associate with this application initially (before
0276      * the user has had any chance to define a profile for it).
0277      * The bigger the value, the stronger the preference for the application.
0278      * @return the service preference level of the application
0279      */
0280     int initialPreference() const;
0281 
0282     /**
0283      * Whether the entry should be hidden from the menu.
0284      * @return @c true to hide this application from the menu
0285      *
0286      * Such services still appear in trader queries, i.e. in
0287      * "Open With" popup menus for instance.
0288      */
0289     bool noDisplay() const;
0290 
0291     /**
0292      * Whether the application should be shown in the current desktop
0293      * (including in context menus).
0294      * @return true if the application should be shown in the current desktop.
0295      *
0296      * KApplicationTrader honors this and removes such services
0297      * from its results.
0298      *
0299      * @since 5.0
0300      */
0301     bool showInCurrentDesktop() const;
0302 
0303     /**
0304      * Whether the application should be shown on the current
0305      * platform (e.g. on xcb or on wayland).
0306      * @return @c true if the application should be shown on the current platform.
0307      *
0308      * @since 5.0
0309      */
0310     bool showOnCurrentPlatform() const;
0311 
0312     /**
0313      * The path to the documentation for this application.
0314      * @since 4.2
0315      * @return the documentation path, or QString() if not set
0316      */
0317     QString docPath() const;
0318 
0319     /**
0320      * Returns the requested property.
0321      *
0322      * @tparam T the type of the requested property.
0323      *
0324      * @param name the name of the property.
0325      *
0326      * @since 6.0
0327      */
0328     template<typename T>
0329     T property(const QString &name) const
0330     {
0331         KServiceConversionCheck::to_QVariant<T>();
0332         return property(name, static_cast<QMetaType::Type>(qMetaTypeId<T>())).value<T>();
0333     }
0334 
0335     /**
0336      * Returns a path that can be used for saving changes to this
0337      * application
0338      * @return path that can be used for saving changes to this application
0339      */
0340     QString locateLocal() const;
0341 
0342     /**
0343      * @internal
0344      * Set the menu id
0345      */
0346     void setMenuId(const QString &menuId);
0347     /**
0348      * @internal
0349      * Sets whether to use a terminal or not
0350      */
0351     void setTerminal(bool b);
0352     /**
0353      * @internal
0354      * Sets the terminal options to use
0355      */
0356     void setTerminalOptions(const QString &options);
0357 
0358     /**
0359      * Overrides the "Exec=" line of the service.
0360      *
0361      * If @ref exec is not empty, its value will override the one
0362      * the one set when this application was created.
0363      *
0364      * Please note that @ref entryPath is also cleared so the application
0365      * will no longer be associated with a specific config file.
0366      *
0367      * @internal
0368      * @since 4.11
0369      */
0370     void setExec(const QString &exec);
0371 
0372     /**
0373      * Overrides the "Path=" line of the application.
0374      *
0375      * If @ref workingDir is not empty, its value will override
0376      * the one set when this application was created.
0377      *
0378      * Please note that @ref entryPath is also cleared so the application
0379      * will no longer be associated with a specific config file.
0380      *
0381      * @internal
0382      * @param workingDir
0383      * @since 5.79
0384      */
0385     void setWorkingDirectory(const QString &workingDir);
0386 
0387     /**
0388      * Find a application based on its path as returned by entryPath().
0389      * It's usually better to use serviceByStorageId() instead.
0390      *
0391      * @param _path the path of the configuration file
0392      * @return a pointer to the requested application or @c nullptr if the application is
0393      *         unknown.
0394      * @em Very @em important: Don't store the result in a KService* !
0395      */
0396     static Ptr serviceByDesktopPath(const QString &_path);
0397 
0398     /**
0399      * Find an application by the name of its desktop file, not depending on
0400      * its actual location (as long as it's under the applications or application
0401      * directories). For instance "konqbrowser" or "kcookiejar". Note that
0402      * the ".desktop" extension is implicit.
0403      *
0404      * This is the recommended method (safe even if the user moves stuff)
0405      * but note that it assumes that no two entries have the same filename.
0406      *
0407      * @param _name the name of the configuration file
0408      * @return a pointer to the requested application or @c nullptr if the application is
0409      *         unknown.
0410      * @em Very @em important: Don't store the result in a KService* !
0411      */
0412     static Ptr serviceByDesktopName(const QString &_name);
0413 
0414     /**
0415      * Find a application by its menu-id
0416      *
0417      * @param _menuId the menu id of the application
0418      * @return a pointer to the requested application or @c nullptr if the application is
0419      *         unknown.
0420      * @em Very @em important: Don't store the result in a KService* !
0421      */
0422     static Ptr serviceByMenuId(const QString &_menuId);
0423 
0424     /**
0425      * Find a application by its storage-id or desktop-file path. This
0426      * function will try very hard to find a matching application.
0427      *
0428      * @param _storageId the storage id or desktop-file path of the application
0429      * @return a pointer to the requested application or @c nullptr if the application is
0430      *         unknown.
0431      * @em Very @em important: Don't store the result in a KService* !
0432      */
0433     static Ptr serviceByStorageId(const QString &_storageId);
0434 
0435     /**
0436      * Returns the whole list of applications.
0437      *
0438      *  Useful for being able to
0439      * to display them in a list box, for example.
0440      * More memory consuming than the ones above, don't use unless
0441      * really necessary.
0442      * @return the list of all applications
0443      */
0444     static List allServices();
0445 
0446     /**
0447      * Returns a path that can be used to create a new KService based
0448      * on @p suggestedName.
0449      * @param showInMenu @c true, if the application should be shown in the KDE menu
0450      *        @c false, if the application should be hidden from the menu
0451      *        This argument isn't used anymore, use `NoDisplay=true` to hide the application.
0452      * @param suggestedName name to base the file on, if an application with such a
0453      *        name already exists, a suffix will be added to make it unique
0454      *        (e.g. foo.desktop, foo-1.desktop, foo-2.desktop).
0455      * @param menuId If provided, menuId will be set to the menu id to use for
0456      *        the KService
0457      * @param reservedMenuIds If provided, the path and menu id will be chosen
0458      *        in such a way that the new menu id does not conflict with any
0459      *        of the reservedMenuIds
0460      * @return The path to use for the new KService.
0461      */
0462     static QString newServicePath(bool showInMenu, const QString &suggestedName, QString *menuId = nullptr, const QStringList *reservedMenuIds = nullptr);
0463 
0464     /**
0465      * @brief A desktop file name that this application is an alias for.
0466      *
0467      * This is used when a `NoDisplay` application is used to enforce specific handling
0468      * for an application. In that case the `NoDisplay` application is an `AliasFor` another
0469      * application and be considered roughly equal to the `AliasFor` application (which should
0470      * not be `NoDisplay=true`)
0471      * For example Okular supplies a desktop file for each supported format (e.g. PDF), all
0472      * of which `NoDisplay` and it is merely there to selectively support specific file formats.
0473      * A UI may choose to display the aliased entry org.kde.okular instead of the NoDisplay entries.
0474      *
0475      * @since 5.96
0476      *
0477      * @return QString desktopName of the aliased application (excluding .desktop suffix)
0478      */
0479     QString aliasFor() const;
0480 
0481     /**
0482      * Returns the value of StartupNotify for this service.
0483      *
0484      * If the service doesn't define a value nullopt is returned.
0485      *
0486      * See StartupNotify in the <a href="https://specifications.freedesktop.org/desktop-entry-spec/latest/">Desktop Entry Specification</a>.
0487      *
0488      * @since 6.0
0489      */
0490     std::optional<bool> startupNotify() const;
0491 
0492 private:
0493     friend class KBuildServiceFactory;
0494 
0495     QVariant property(const QString &_name, QMetaType::Type t) const;
0496 
0497     /// @internal for KBuildSycoca only
0498     struct KSERVICE_NO_EXPORT ServiceTypeAndPreference {
0499         ServiceTypeAndPreference()
0500             : preference(-1)
0501             , serviceType()
0502         {
0503         }
0504         ServiceTypeAndPreference(int pref, const QString &servType)
0505             : preference(pref)
0506             , serviceType(servType)
0507         {
0508         }
0509         int preference;
0510         QString serviceType; // or MIME type
0511     };
0512     /// @internal for KBuildSycoca only
0513     QList<ServiceTypeAndPreference> _k_accessServiceTypes();
0514 
0515     void setActions(const QList<KServiceAction> &actions);
0516 
0517     friend QDataStream &operator>>(QDataStream &, ServiceTypeAndPreference &);
0518     friend QDataStream &operator<<(QDataStream &, const ServiceTypeAndPreference &);
0519 
0520     Q_DECLARE_PRIVATE(KService)
0521 
0522     friend class KServiceFactory;
0523 
0524     /**
0525      * @internal
0526      * Construct a service from a stream.
0527      * The stream must already be positioned at the correct offset.
0528      */
0529     KSERVICE_NO_EXPORT KService(QDataStream &str, int offset);
0530 };
0531 
0532 template<>
0533 KSERVICE_EXPORT QString KService::property<QString>(const QString &name) const;
0534 
0535 #endif