Development/Tutorials/Services/Introduction

From KDE TechBase


Introduction to the Services Framework

Abstract

Services represent applications, plugins and other add-ons available on the system. They make it easy to find, launch and load the items they represent without having to hardcode any specific component or even know ahead of time what services will be available. This tutorial covers what the services system provides and where the information is stored.

Advantages of Using Services

There are three main advantages to using services:

  • it's simple
  • it's future proof
  • it's flexible

Whenever your application needs to launch another desktop application, find available applications, load plugins or find application add-ons it's as simple as a few lines of code to do so and the code is quite similar regardless of what you are looking for.

Since most of the details involved in looking up services are hidden away from your application, if things change either due to time and new standards or platform specific features your code will continue to work. For instance, when KDE implemented the freedesktop.org specification for describing application launcher menu structures, application code that had been functioning previous to this continued to function without any changes or even a recompile.

Best of all, the services system provides a flexible system under the hood for users and administrators to be able to customize, add new entries, remove existing items and even lock down access without putting any burden of complexity on application developers.

Classes At A Glance

The main services related classes that applications are likely to use are generally limited to the following two:

  • KService: represents one application, plugin or add on
  • KServiceTypeTrader: allows discovery of available services through a simple query language; this class and the query language is covered in detail in the next tutorial

Other classes that are available but less often used by applications include:

  • KServiceOffer: provides information on user preference for a given service; primarly used for mimetypes
  • KServiceType: provides access to information about a given type of service
  • KServiceTypeProfile: represents the user's preferences between multiple services of the same type; this is used internally by KServiceTypeTrader

KService

The KService class is at the center of the services system. It serves both an informational and a functional role. KService provides access to details on a given service such as whether it is an application, the name of the service, the associated icon (if any), etc. But it can also be used to launch applications and load plugins from disk.

A KService object can be obtained in one of three ways:

  • creating one manually
  • requesting one by name
  • querying

The first approach is the most straightforward and often looks something like this:

QString pathToDesktopFile = KStandardDirs::locate("services", "konqueror.desktop");
KService service(pathToDesktopFile);

KService also provides ways to load services by name directly with the serviceBy* set of methods, of which the safest and most recommended is serviceByStorageId:

KService::Ptr service = KService::serviceByStorageId("konqueror");

Note that it passed back a KService::Ptr rather than just a KService. A KService::Ptr looks, acts and behaves just like a regular pointer (KService*) but it is automatically memory managed. It is not necessary to manually delete KService::Ptrs, because they are reference counted.

A list of all services can be retrieved using the KService::allServices method. Of course, one often wants finer grained control over locating services, which is the role of the KServiceTypeTrader and is the topic of the next tutorial in this series.

At this point we now have access to all sorts of information on the service, which in this case is an application called konqueror. We can even launch the app using this service:

Note
With KF5 the following code will change. E.g. KUrl is replaced by QUrl. Basic call: `KRun::run(*service, QList<QUrl>(), nullptr);`


if (service.isApplication()) {
    KUrl::List urls;
    urls << "http://www.kde.org";
    KRun::run(service, urls, 0);
}

This would launch konqueror and cause it to open the KDE homepage.

Registering Services

Services are represented on disk as individual .desktop files. This makes it easy to add, remove, and customize services on the system. The .desktop files are organized by their type of service. Applications, plugins, protocols, and mimetypes are each kept in their own directories. The location of these directories is documented in the KDE Filesystem Hierarchy page. Installation is usually automated through the build system, such as CMake in KDE4.

Services may also have one or more "service types" that are used to categorize and search for them. While applications and mimetypes don't utilize this, plugins and other services do. These service types are registered by placing a .desktop file describing the service type in the correct location in the filesystem, usually share/kde4/servicetypes. See the KDE Filesystem Hierarchy page for more information.

The content and form of these .desktop files is covered in detail in the Creating and Loading Plugins Using KService tutorial.

SyCoCa: The System Configuration Cache

While the .desktop (file) method is very handy for users (and adding new entries), performance could be an issue because it is common to have thousands of these files describing various mimetypes, applications, plugins, screensavers, etc. Thus, the entries are put into a binary cache which is accessed via shared memory by all applications. The cache is known as the System Configuration Cache, or SyCoCa for short. Loading and locating KServices is done via this cache, transparently to the application.

Whenever a new .desktop file is added, removed or altered, the cache is automatically updated by the kbuildsycoca4 application. You can force an update of the cache by running kbuildsycoca4 manually, though usually it is launched by kded4 automatically when needed. A full rebuild of the cache (versus a simple update) can be triggered by passing --noincremental to kbuildsycoca4.

Searching For Services

The next tutorial is Finding Services Using Trader Queries. We will look at how to find services using the KTrader query language and KServiceTypeTrader .