Settings module development

This tutorial will guide you into creating a Plasma configuration module.

Introduction

Settings in Plasma are provided by Configuration Modules (KCM). These can be loaded by multiple wrapper applications such as systemsettings5 on the desktop, plasma-settings on mobile or kcmshell5 for standalone config windows.

You can query the available KCMs using kcmshell5 --list. To load an individual module in a standalone window pass its name to kcmshell5, e.g. kcmshell5 kcm_kaccounts. To open it in plasma-settings use the -m parameter, e.g. plasma-settings -m kcm_kaccounts.

Basic KCM

KCMs consist of a KPackage holding the QML UI and a C++ library holding the logic. Some legacy KCMs are based on QtWidgets, however this is not recommended for new KCMs and it’s not possible to load these in plasma-settings.

The basic structure of a hypothetical time settings module is the following:

├── CMakeLists.txt
├── timesettings.{cpp,h}
└── package
    ├── metadata.desktop
    └── contents/ui
        └── main.qml

CMakeLists.txt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# SPDX-FileCopyrightText: Year Author <email@company.com>
#
# SPDX-License-Identifier: BSD-2-Clause

cmake_minimum_required(VERSION 3.0)

project(timekcm)

set(QT_MIN_VERSION "5.14.0")
set(KF5_MIN_VERSION "5.73.0")

find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)

include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)

find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
    Quick
    Svg
)

find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
    I18n
    KCMUtils
    Declarative
    Config
)

set(timesettings_SRCS
    timesettings.cpp
)

add_library(kcm_time MODULE ${timesettings_SRCS})

target_link_libraries(kcm_time
    Qt5::Core
    KF5::CoreAddons
    KF5::I18n
    KF5::QuickAddons
)

kcoreaddons_desktop_to_json(kcm_time "package/metadata.desktop")

install(TARGETS kcm_time DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms)
install(FILES package/metadata.desktop RENAME kcm_time.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) # Install the desktop file


kpackage_install_package(package kcm_time kcms) # Install our QML kpackage.

timesettings.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/**
 * SPDX-FileCopyrightText: Year Author <author@domanin.com>
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#pragma once

#include <KQuickAddons/ManagedConfigModule>

class TimeSettings : public KQuickAddons::ManagedConfigModule
{
    Q_OBJECT
public:
    TimeSettings(QObject *parent, const QVariantList &args);
    virtual ~TimeSettings() override = default;
};

KQuickAddons::ConfigModule serves as the base class for all QML-based KCMs. The KQuickAddons::ManagedConfigModule inherits ConfigModule and adds the KConfigXt integration. Please consult the API documentation for a full description.

timesettings.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
 * SPDX-FileCopyrightText: Year Author <author@domain.com>
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include "timesettings.h"

#include <KPluginFactory>
#include <KLocalizedString>
#include <KAboutData>

K_PLUGIN_CLASS_WITH_JSON(TimeSettings, "metadata.json")

TimeSettings::TimeSettings(QObject *parent, const QVariantList &args)
    : KQuickAddons::ManagedConfigModule(parent, args)
{
    KAboutData *aboutData = new KAboutData(QStringLiteral("kcm_time"),
        i18nc("@title", "Time"),
        QStringLiteral("0.1"),
        QStringLiteral(""),
        KAboutLicense::LicenseKey::GPL_V2,
        i18nc("@info:credit", "Copyright Year Author"));

    aboutData->addAuthor(i18nc("@info:credit", "Author"),
                        i18nc("@info:credit", "Author"),
                        QStringLiteral("author@domain.com"));

    setAboutData(aboutData);
    setButtons(Help | Apply | Default);
}

#include "timesettings.moc"

package/metadata.desktop

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
[Desktop Entry]
Name=Time
Comment=Configure Time
Encoding=UTF-8
Type=Service
Icon=preferences-system-time
X-KDE-Library=kcm_time
X-KDE-ServiceTypes=KCModule
X-KDE-FormFactors=desktop,handset,tablet,mediacenter
X-Plasma-MainScript=ui/main.qml
X-KDE-System-Settings-Parent-Category=personalization
X-KDE-Keywords=Time,Date,Clock
X-KDE-ParentApp=kcontrol

Example metadata file

  • Name defines the name of the KCM which is shown in the settings app.
  • Description is a short, one sentence description of the module.
  • X-KDE-Library must match the library name defined in CMakeLists.txt.
  • X-KDE-FormFactors defines on which kinds of devices this KCM should be shown.
  • X-Plasma-MainScript points to the main QML file in the KPackage.
  • X-KDE-System-Settings-Parent-Category defines the category systemsettings5 is showing the module in.
  • X-KDE-Keywords defines Keywords used for searching modules.

package/contents/ui/main.qml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/**
 * SPDX-FileCopyrightText: Year Author <author@domanin.com>
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

import QtQuick 2.12
import QtQuick.Controls 2.12 as Controls

import org.kde.kirigami 2.7 as Kirigami
import org.kde.kcm 1.2

SimpleKCM {
    Controls.Label {
        text: i18n("Configure Time")
    }
}

Basic KCM QML file

Depending on the content use one of the following root type:

Run it!

mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=~/.local/kde
make -j8 install
kcmshell5 kcm_time

the time kcm running

Multi-page KCM

KCMs can consist of multiple pages that are dynamically opened and closed. To push another page use

kcm.push("AnotherPage.qml")

AnotherPage.qml should have one of the above types as root element. To pop a page use

kcm.pop()