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 6 SPDX-License-Identifier: LGPL-2.0-or-later 7 */ 8 9 #ifndef KSERVICE_H 10 #define KSERVICE_H 11 12 #include "kserviceaction.h" 13 #include <KPluginFactory> 14 #include <KPluginLoader> 15 #include <QCoreApplication> 16 #include <QStringList> 17 #include <QVariant> 18 #include <ksycocaentry.h> 19 20 class KServiceType; 21 class QDataStream; 22 class KDesktopFile; 23 class QWidget; 24 25 class KServicePrivate; 26 27 /** 28 * @class KService kservice.h <KService> 29 * 30 * Represent a service, like an application or plugin 31 * bound to one or several MIME types (or servicetypes) as written 32 * in its desktop entry file. 33 * 34 * The starting point you need is often the static methods, like createInstance(). 35 * The types of service a plugin provides is taken from the accompanying desktop file 36 * where the 'X-KDE-ServiceTypes=' field is used. 37 * 38 * For a tutorial on how to build a plugin-loading mechanism and how to write plugins 39 * in general, see http://techbase.kde.org/Development/Tutorials#Services:_Applications_and_Plugins 40 * 41 * @see KServiceType 42 * @see KServiceGroup 43 * @author Torben Weis 44 */ 45 class KSERVICE_EXPORT KService : public KSycocaEntry 46 { 47 public: 48 /** 49 * A shared data pointer for KService. 50 */ 51 typedef QExplicitlySharedDataPointer<KService> Ptr; 52 /** 53 * A list of shared data pointers for KService. 54 */ 55 typedef QList<Ptr> List; 56 57 /** 58 * Construct a temporary service with a given name, exec-line and icon. 59 * @param name the name of the service 60 * @param exec the executable 61 * @param icon the name of the icon 62 */ 63 KService(const QString &name, const QString &exec, const QString &icon); 64 65 /** 66 * Construct a service and take all information from a config file. 67 * 68 * @param fullpath Full path to the config file. 69 */ 70 explicit KService(const QString &fullpath); 71 72 /** 73 * Construct a service and take all information from a desktop file. 74 * @param config the desktop file to read 75 * @param optional relative path to store for findByName 76 */ 77 explicit KService(const KDesktopFile *config, const QString &entryPath = QString()); 78 79 KService(const KService &other); 80 81 ~KService() override; 82 83 /** 84 * Services are either applications (executables) or dlopened libraries (plugins). 85 * @return true if this service is an application, i.e. it has Type=Application in its 86 * .desktop file and exec() will not be empty. 87 */ 88 bool isApplication() const; 89 90 /** 91 * Returns the executable. 92 * @return the command that the service executes, 93 * or QString() if not set 94 */ 95 QString exec() const; 96 /** 97 * Returns the name of the service's library. 98 * @return the name of the library that contains the service's 99 * implementation, or QString() if not set 100 */ 101 QString library() const; 102 103 /** 104 * Returns the name of the icon. 105 * @return the icon associated with the service, 106 * or QString() if not set 107 */ 108 QString icon() const; 109 /** 110 * Checks whether the service should be run in a terminal. 111 * @return true if the service is to be run in a terminal. 112 */ 113 bool terminal() const; 114 115 /** 116 * Returns any options associated with the terminal the service 117 * runs in, if it requires a terminal. 118 * 119 * The service must be a tty-oriented program. 120 * @return the terminal options, 121 * or QString() if not set 122 */ 123 QString terminalOptions() const; 124 125 /** 126 * Returns @c true if the service inidicates that it's preferred to run 127 * the application on a discrete graphics card, otherwise return @c false. 128 * 129 * In releases older than 5.86 this methoed checked for the @c X-KDE-RunOnDiscreteGpu 130 * key in the .desktop file represented by this service; starting from 5.86 this method 131 * now also checks for @c PrefersNonDefaultGPU key (added to the Freedesktop.org desktop 132 * entry spec in version 1.4 of the spec). 133 * 134 * @since 5.30 135 */ 136 bool runOnDiscreteGpu() const; 137 138 /** 139 * Checks whether the service runs with a different user id. 140 * @return true if the service has to be run under a different uid. 141 * @see username() 142 */ 143 bool substituteUid() const; 144 /** 145 * Returns the user name, if the service runs with a 146 * different user id. 147 * @return the username under which the service has to be run, 148 * or QString() if not set 149 * @see substituteUid() 150 */ 151 QString username() const; 152 153 /** 154 * Returns the filename of the service desktop entry without any 155 * extension. E.g. "kppp" 156 * @return the name of the desktop entry without path or extension, 157 * or QString() if not set 158 */ 159 QString desktopEntryName() const; 160 161 /** 162 * Returns the menu ID of the service desktop entry. 163 * The menu ID is used to add or remove the entry to a menu. 164 * @return the menu ID 165 */ 166 QString menuId() const; 167 168 /** 169 * Returns a normalized ID suitable for storing in configuration files. 170 * It will be based on the menu-id when available and otherwise falls 171 * back to entryPath() 172 * @return the storage ID 173 */ 174 QString storageId() const; 175 176 /** 177 * Describes the D-Bus Startup type of the service. 178 * @li None - This service has no D-Bus support 179 * @li Unique - This service provides a unique D-Bus service. 180 * The service name is equal to the desktopEntryName. 181 * @li Multi - This service provides a D-Bus service which can be run 182 * with multiple instances in parallel. The service name of 183 * an instance is equal to the desktopEntryName + "-" + 184 * the PID of the process. 185 */ 186 enum DBusStartupType { DBusNone = 0, DBusUnique, DBusMulti }; 187 188 /** 189 * Returns the DBUSStartupType supported by this service. 190 * @return the DBUSStartupType supported by this service 191 */ 192 DBusStartupType dbusStartupType() const; 193 194 #if KSERVICE_ENABLE_DEPRECATED_SINCE(5, 63) 195 /** 196 * @return the working directory to run the program in, 197 * or QString() if not set 198 * @deprecated since 5.63, use workingDirectory() instead 199 */ 200 KSERVICE_DEPRECATED_VERSION(5, 63, "Use KService::workingDirectory()") 201 QString path() const; 202 #endif 203 204 /** 205 * @return the working directory to run the program in, 206 * or QString() if not set 207 * @since 5.63 208 */ 209 QString workingDirectory() const; 210 211 /** 212 * Returns the descriptive comment for the service, if there is one. 213 * @return the descriptive comment for the service, or QString() 214 * if not set 215 */ 216 QString comment() const; 217 218 /** 219 * Returns the generic name for the service, if there is one 220 * (e.g. "Mail Client"). 221 * @return the generic name, 222 * or QString() if not set 223 */ 224 QString genericName() const; 225 226 /** 227 * Returns the untranslated (US English) generic name 228 * for the service, if there is one 229 * (e.g. "Mail Client"). 230 * @return the generic name, 231 * or QString() if not set 232 */ 233 QString untranslatedGenericName() const; 234 235 /** 236 * Returns a list of descriptive keywords the service, if there are any. 237 * @return the list of keywords 238 */ 239 QStringList keywords() const; 240 241 /** 242 * Returns a list of VFolder categories. 243 * @return the list of VFolder categories 244 */ 245 QStringList categories() const; 246 247 /** 248 * Returns the list of MIME types that this service supports. 249 * Note that this doesn't include inherited MIME types, 250 * only the MIME types types listed in the .desktop file. 251 * @since 4.8.3 252 */ 253 QStringList mimeTypes() const; 254 255 /** 256 * Returns the service types that this service supports. 257 * @return the list of service types that are supported 258 * Note that this doesn't include inherited servicetypes or MIME types, 259 * only the service types listed in the .desktop file. 260 */ 261 QStringList serviceTypes() const; 262 263 /** 264 * Checks whether the service supports this service type 265 * @param serviceTypePtr The name of the service type you are 266 * interested in determining whether this service supports. 267 * 268 * @return true if the service type you specified is supported, otherwise false. 269 */ 270 bool hasServiceType(const QString &serviceTypePtr) const; 271 272 /** 273 * Checks whether the service supports this MIME type 274 * @param mimeType The name of the MIME type you are 275 * interested in determining whether this service supports. 276 * @since 4.6 277 */ 278 bool hasMimeType(const QString &mimeType) const; 279 280 #if KSERVICE_ENABLE_DEPRECATED_SINCE(5, 67) 281 /** 282 * Set to true if it is allowed to use this service as the default (main) 283 * action for the files it supports (e.g. Left Click in a file manager, or KRun in general). 284 * 285 * If not, then this service is only available in RMB popups, so it must 286 * be selected explicitly by the user in order to be used. 287 * Note that servicemenus supersede this functionality though, at least in konqueror. 288 * 289 * @return true if the service may be used as the default (main) handler 290 * @deprecated since 5.67 due to no known use case 291 */ 292 KSERVICE_DEPRECATED_VERSION(5, 67, "No known use case") 293 bool allowAsDefault() const; 294 #endif 295 296 /** 297 * Returns the actions defined in this desktop file 298 */ 299 QList<KServiceAction> actions() const; 300 301 /** 302 * Checks whether this service can handle several files as 303 * startup arguments. 304 * @return true if multiple files may be passed to this service at 305 * startup. False if only one file at a time may be passed. 306 */ 307 bool allowMultipleFiles() const; 308 309 /** 310 * What preference to associate with this service initially (before 311 * the user has had any chance to define a profile for it). 312 * The bigger the value, the most preferred the service is. 313 * @return the service preference level of the service 314 */ 315 int initialPreference() const; 316 317 /** 318 * Whether the entry should be suppressed in the K menu. 319 * @return true to suppress this service 320 * 321 * Such services still appear in trader queries, i.e. in 322 * "Open With" popup menus for instance. 323 */ 324 bool noDisplay() const; 325 326 #if KSERVICE_ENABLE_DEPRECATED_SINCE(5, 0) 327 /** 328 * Whether the service should be shown in KDE at all 329 * (including in context menus). 330 * @return true if the service should be shown. 331 * 332 * KMimeTypeTrader honors this and removes such services 333 * from its results. 334 * 335 * @since 4.5 336 * @deprecated since 5.0, use showInCurrentDesktop() 337 */ 338 KSERVICE_DEPRECATED_VERSION(5, 0, "Use KService::showInCurrentDesktop()") showInKDE()339 bool showInKDE() const 340 { 341 return showInCurrentDesktop(); 342 } 343 #endif 344 345 /** 346 * Whether the service should be shown in the current desktop 347 * (including in context menus). 348 * @return true if the service should be shown. 349 * 350 * KApplicationTrader honors this and removes such services 351 * from its results. 352 * 353 * @since 5.0 354 */ 355 bool showInCurrentDesktop() const; 356 357 /** 358 * Whether the service should be shown on the current 359 * platform (e.g. on xcb or on wayland). 360 * @return true if the service should be shown 361 * 362 * @since 5.0 363 */ 364 bool showOnCurrentPlatform() const; 365 366 #if KSERVICE_ENABLE_DEPRECATED_SINCE(5, 87) 367 /** 368 * Name of the application this service belongs to. 369 * (Useful for e.g. plugins) 370 * @return the parent application, or QString() if not set 371 * @deprecated Since 5.87, the concept of parent apps is deprecated. Plugins should use KPluginMetaData instead of 372 * KService and a dedicated namespace if the plugins are only for one app relevant. 373 */ 374 KSERVICE_DEPRECATED_VERSION(5, 87, "See API docs") 375 QString parentApp() const; 376 #endif 377 378 #if KSERVICE_ENABLE_DEPRECATED_SINCE(5, 87) 379 /** 380 * The keyword to be used when constructing the plugin using KPluginFactory. The keyword is 381 * defined with X-KDE-PluginKeyword in the .desktop file and with registerPlugin<T>(keyword) 382 * in the K_PLUGIN_FACTORY macro when implementing the plugin. 383 * @deprecated Since 5.87, the metadata should be embedded in the actual plugin. Consequently 384 * this property is obsolete. In case there is only one plugin in the library the usage is not needed. 385 * In case there are different base classes registered the keyword is not needed too. 386 * If there are multiple classes of a common base class registered they should be split up 387 * in separate libs. 388 */ 389 KSERVICE_DEPRECATED_VERSION(5, 87, "See API docs") 390 QString pluginKeyword() const; 391 #endif 392 393 /** 394 * The path to the documentation for this service. 395 * @since 4.2 396 * @return the documentation path, or QString() if not set 397 */ 398 QString docPath() const; 399 400 /** 401 * Returns the requested property. 402 * 403 * @param _name the name of the property 404 * @param t the assumed type of the property 405 * @return the property, or invalid if not found 406 * @see KServiceType 407 */ 408 QVariant property(const QString &_name, QVariant::Type t) const; 409 410 using KSycocaEntry::property; 411 412 /** 413 * Returns a path that can be used for saving changes to this 414 * service 415 * @return path that can be used for saving changes to this service 416 */ 417 QString locateLocal() const; 418 419 /** 420 * @internal 421 * Set the menu id 422 */ 423 void setMenuId(const QString &menuId); 424 /** 425 * @internal 426 * Sets whether to use a terminal or not 427 */ 428 void setTerminal(bool b); 429 /** 430 * @internal 431 * Sets the terminal options to use 432 */ 433 void setTerminalOptions(const QString &options); 434 435 /** 436 * Overrides the "Exec=" line of the service. 437 * 438 * If @ref exec is not empty, its value will override the one 439 * the one set when this service was created. 440 * 441 * Please note that @ref entryPath is also cleared so the service 442 * will no longer be associated with a specific config file. 443 * 444 * @internal 445 * @since 4.11 446 */ 447 void setExec(const QString &exec); 448 449 /** 450 * Overrides the "Path=" line of the service. 451 * 452 * If @ref workingDir is not empty, its value will override the one 453 * the one set when this service was created. 454 * 455 * Please note that @ref entryPath is also cleared so the service 456 * will no longer be associated with a specific config file. 457 * 458 * @internal 459 * @param workingDir 460 * @since 5.79 461 */ 462 void setWorkingDirectory(const QString &workingDir); 463 464 /** 465 * Find a service based on its path as returned by entryPath(). 466 * It's usually better to use serviceByStorageId() instead. 467 * 468 * @param _path the path of the configuration file 469 * @return a pointer to the requested service or @c nullptr if the service is 470 * unknown. 471 * @em Very @em important: Don't store the result in a KService* ! 472 */ 473 static Ptr serviceByDesktopPath(const QString &_path); 474 475 /** 476 * Find a service by the name of its desktop file, not depending on 477 * its actual location (as long as it's under the applications or service 478 * directories). For instance "konqbrowser" or "kcookiejar". Note that 479 * the ".desktop" extension is implicit. 480 * 481 * This is the recommended method (safe even if the user moves stuff) 482 * but note that it assumes that no two entries have the same filename. 483 * 484 * @param _name the name of the configuration file 485 * @return a pointer to the requested service or @c nullptr if the service is 486 * unknown. 487 * @em Very @em important: Don't store the result in a KService* ! 488 */ 489 static Ptr serviceByDesktopName(const QString &_name); 490 491 /** 492 * Find a service by its menu-id 493 * 494 * @param _menuId the menu id of the service 495 * @return a pointer to the requested service or @c nullptr if the service is 496 * unknown. 497 * @em Very @em important: Don't store the result in a KService* ! 498 */ 499 static Ptr serviceByMenuId(const QString &_menuId); 500 501 /** 502 * Find a service by its storage-id or desktop-file path. This 503 * function will try very hard to find a matching service. 504 * 505 * @param _storageId the storage id or desktop-file path of the service 506 * @return a pointer to the requested service or @c nullptr if the service is 507 * unknown. 508 * @em Very @em important: Don't store the result in a KService* ! 509 */ 510 static Ptr serviceByStorageId(const QString &_storageId); 511 512 /** 513 * Returns the whole list of services. 514 * 515 * Useful for being able to 516 * to display them in a list box, for example. 517 * More memory consuming than the ones above, don't use unless 518 * really necessary. 519 * @return the list of all services 520 */ 521 static List allServices(); 522 523 /** 524 * Returns a path that can be used to create a new KService based 525 * on @p suggestedName. 526 * @param showInMenu true, if the service should be shown in the KDE menu 527 * false, if the service should be hidden from the menu 528 * This argument isn't used anymore, use NoDisplay=true to hide the service. 529 * @param suggestedName name to base the file on, if a service with such a 530 * name already exists, a suffix will be added to make it unique 531 * (e.g. foo.desktop, foo-1.desktop, foo-2.desktop). 532 * @param menuId If provided, menuId will be set to the menu id to use for 533 * the KService 534 * @param reservedMenuIds If provided, the path and menu id will be chosen 535 * in such a way that the new menu id does not conflict with any 536 * of the reservedMenuIds 537 * @return The path to use for the new KService. 538 */ 539 static QString newServicePath(bool showInMenu, const QString &suggestedName, QString *menuId = nullptr, const QStringList *reservedMenuIds = nullptr); 540 541 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 86) 542 #if KSERVICE_ENABLE_DEPRECATED_SINCE(5, 86) 543 /** 544 * This template allows to load the library for the specified service and ask the 545 * factory to create an instance of the given template type. 546 * 547 * @param parent The parent object (see QObject constructor) 548 * @param args A list of arguments, passed to the factory and possibly 549 * to the component (see KPluginFactory) 550 * @param error A pointer to QString which should receive the error description or @c nullptr 551 * 552 * @return A pointer to the newly created object or a null pointer if the 553 * factory was unable to create an object of the given type. 554 * 555 * @see KPluginFactory::instantiatePlugin 556 * @deprecated Since 5.86, Use KPluginMetaData/KPluginFactory or QPluginloader instead 557 */ 558 template<class T> 559 KSERVICE_DEPRECATED_VERSION(5, 86, "Use KPluginMetaData/KPluginFactory or QPluginloader instead") 560 T *createInstance(QObject *parent = nullptr, const QVariantList &args = QVariantList(), QString *error = nullptr) const 561 { 562 return createInstance<T>(nullptr, parent, args, error); 563 } 564 #endif 565 #endif 566 567 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 86) 568 #if KSERVICE_ENABLE_DEPRECATED_SINCE(5, 86) 569 /** 570 * This template allows to load the library for the specified service and ask the 571 * factory to create an instance of the given template type. 572 * 573 * @param parentWidget A parent widget for the service. This is used e. g. for parts 574 * @param parent The parent object (see QObject constructor) 575 * @param args A list of arguments, passed to the factory and possibly 576 * to the component (see KPluginFactory) 577 * @param error A pointer to QString which should receive the error description or @c nullptr 578 * 579 * @return A pointer to the newly created object or a null pointer if the 580 * factory was unable to create an object of the given type. 581 * 582 * @see KPluginFactory::instantiatePlugin 583 * @deprecated Since 5.86, Use KPluginMetaData/KPluginFactory or QPluginloader instead 584 */ 585 template<class T> 586 KSERVICE_DEPRECATED_VERSION(5, 86, "Use KPluginMetaData/KPluginFactory or QPluginloader instead") 587 T *createInstance(QWidget *parentWidget, QObject *parent, const QVariantList &args = QVariantList(), QString *error = nullptr) const 588 { 589 QT_WARNING_PUSH 590 QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") 591 QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") 592 KPluginLoader pluginLoader(*this); 593 KPluginFactory *factory = pluginLoader.factory(); 594 if (factory) { 595 QVariantList argsWithMetaData = args; 596 argsWithMetaData << pluginLoader.metaData().toVariantMap(); 597 T *o = factory->template create<T>(parentWidget, parent, pluginKeyword(), argsWithMetaData); 598 if (!o && error) 599 *error = QCoreApplication::translate("", "The service '%1' does not provide an interface '%2' with keyword '%3'") 600 .arg(name(), QString::fromLatin1(T::staticMetaObject.className()), pluginKeyword()); 601 return o; 602 } else if (error) { 603 *error = pluginLoader.errorString(); 604 pluginLoader.unload(); 605 } 606 QT_WARNING_POP 607 return nullptr; 608 } 609 #endif 610 #endif 611 612 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 86) 613 #if KSERVICE_ENABLE_DEPRECATED_SINCE(5, 86) 614 /** 615 * Convert this KService to a KPluginName. 616 * 617 * This allows expressions like 618 * @code 619 * KPluginLoader(service); 620 * @endcode 621 * which will use library() as the name of the plugin. If the service 622 * is not valid or does not have a library, KPluginLoader::errorString() 623 * will be set appropriately. 624 */ 625 operator KPluginName() const; 626 #endif 627 #endif 628 629 private: 630 friend class KBuildServiceFactory; 631 632 /// @internal for KBuildSycoca only 633 struct ServiceTypeAndPreference { ServiceTypeAndPreferenceServiceTypeAndPreference634 ServiceTypeAndPreference() 635 : preference(-1) 636 , serviceType() 637 { 638 } ServiceTypeAndPreferenceServiceTypeAndPreference639 ServiceTypeAndPreference(int pref, const QString &servType) 640 : preference(pref) 641 , serviceType(servType) 642 { 643 } 644 int preference; 645 QString serviceType; // or MIME type 646 }; 647 /// @internal for KBuildSycoca only 648 QVector<ServiceTypeAndPreference> &_k_accessServiceTypes(); 649 650 friend QDataStream &operator>>(QDataStream &, ServiceTypeAndPreference &); 651 friend QDataStream &operator<<(QDataStream &, const ServiceTypeAndPreference &); 652 653 Q_DECLARE_PRIVATE(KService) 654 655 friend class KServiceFactory; 656 657 /** 658 * @internal 659 * Construct a service from a stream. 660 * The stream must already be positioned at the correct offset. 661 */ 662 KService(QDataStream &str, int offset); 663 }; 664 #endif 665