Development/Tutorials/KCM HowTo: Difference between revisions

From KDE TechBase
(→‎KCMultiDialog: Update targets for Class templates)
 
(27 intermediate revisions by 5 users not shown)
Line 1: Line 1:
{{Review|Port to KF5}}
{{TutorialBrowser|
series=Plugins and KParts|
name=KCM HowTo|
pre=|
next=|
reading=[http://api.kde.org/4.x-api/kdelibs-apidocs/kdeui/html/classKCModule.html KCModule Class Reference]
}}
==Introduction==
==Introduction==


This HOWTO describes how to write KConfig Modules (KCMs from now on). These KCM
This howto describes how to write KConfig Modules (KCMs from now on). These KCM
can appear in System Settings or in the configuration dialog of individual applications.
can appear in System Settings or in the configuration dialog of individual applications.


Line 12: Line 27:
Implementing a KCM is done by:
Implementing a KCM is done by:
# Subclassing the {{class|KCModule}} class. In this documentation we assume the class inheriting from KCModule is named FooKcm.
# Subclassing the {{class|KCModule}} class. In this documentation we assume the class inheriting from KCModule is named FooKcm.
# Exporting the module so that System Settings or kcmshell4 can find it.
# Exporting the module so that System Settings or kcmshell5 can find it.


The prefered way to export the module is through {{class|KPluginFactory}}. Here is how to
The prefered way to export the module is through {{class|KPluginFactory}}. Here is how to
Line 21: Line 36:


     K_PLUGIN_FACTORY(FooKcmFactory, registerPlugin<FooKcm>();)
     K_PLUGIN_FACTORY(FooKcmFactory, registerPlugin<FooKcm>();)
     K_EXPORT_PLUGIN(FooKcmFactory("kcm_foo", "kcm_foo"))
     K_EXPORT_PLUGIN(FooKcmFactory("kcm_foo" /* kcm name */, "kcm_foo" /* catalog name */))
</syntaxhighlight>
</syntaxhighlight>


Line 55: Line 70:
===Initializing on startup===
===Initializing on startup===


If your module needs to initialize on KDE session startup, you must have a
It is possible to get code from the KCM to be run at startup by kcminit.
construct like:
 
To do so you must declare a function named "kcminit_${module}", like this:


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
     extern "C"
     extern "C"
     {
     {
         KCModule *init_foo(QWidget *parent, const char *name)
         KDEEXPORT void kcminit_foo()
         {
         {
             // Do initialization here
             // Do initialization here
Line 68: Line 84:
</syntaxhighlight>
</syntaxhighlight>


Don't forget to add a "X-KDE-Init" key to your desktop file. (see below)
You must also add a "X-KDE-Init-Symbol" key to your desktop file. (see below)


==The desktop file==
==The desktop file==
Line 84: Line 100:


;X-KDE-ServiceTypes
;X-KDE-ServiceTypes
Should be "KCModule".
Should be "KCModule" for most KCM. If you want to use the kcminit feature it should be "KCModule,KCModuleInit".


;Icon
;Icon
Line 90: Line 106:


;Exec
;Exec
Should be "kcmshell4 foo".
Should be "kcmshell5 foo".


;Name
;Name
Line 104: Line 120:


;X-KDE-ParentApp
;X-KDE-ParentApp
The application you put in this entry determines in what situations it will
Set this to "kcontrol" if you want your KCM to show up in System Settings.
show. For example, if the line says "X-KDE-ParentApp=kcontrol" the module will
 
show up in KControl. It is very crucial the selected ParentApp is correct,
The application you put in this key determines in what situations your KCM will
otherwise the KCM will show up in unnecessary places.
show. It is crucial to select a correct ParentApp, otherwise the KCM will show up in unnecessary places.


;X-KDE-System-Settings-Parent-Category
;X-KDE-System-Settings-Parent-Category
Defines where the KCM will appear in System Settings.
Defines where the KCM will appear in System Settings.
(FIXME: Where is the category list?)
 
Possible values at the time of this writing are:
* settings-lost-and-found
* settings-hardware
* settings-network-and-connectivity
* settings-system-administration
* settings-application-appearance-and-behavior
* settings-workspace-appearance-and-behavior
 
You can get a list of possible categories with this command, which lists all toplevel categories:
 
<pre>
ktraderclient --servicetype SystemSettingsCategory --constraint "[X-KDE-System-Settings-Parent-Category] == ''" | grep DesktopEntryName
</pre>
 
Just do not use the "settings-lost-and-found" entry.


;X-KDE-Keywords
;X-KDE-Keywords
Line 118: Line 149:


;X-KDE-Library
;X-KDE-Library
This is the name of the library, without the kcm_ prefix. So in the example,
This is the name of the library, without the "kcm_" prefix. In our example,
it should be "foo".
it should be "foo".


Line 125: Line 156:


;X-KDE-FactoryName
;X-KDE-FactoryName
This entry can be used to set the name of the factory function in the library.
This entry can be used to set the name of the factory function in the library. If you only have one KCModule in a library this key is not needed. If you have several KCMs in one library you will need a desktop file for each KCM.
If you only have one KCModule in a library this key is not needed. If
you have several KCMs in one library you will need a desktop file for each
KCM.


For example, if you have a library named: kcm_frog.so with two modules, named
For example, if you have a library named: kcm_frog.so with two modules, named "kermit" and "quak", kcm_kermit.desktop would contain:
"kermit" and "quak", kcm_kermit.desktop would contain:


<syntaxhighlight lang="ini">
<syntaxhighlight lang="ini">
Line 147: Line 174:
The module loader would then call the "create_kermit" and "create_quak" functions respectively.
The module loader would then call the "create_kermit" and "create_quak" functions respectively.


;X-KDE-RootOnly
;X-KDE-Init-Symbol
If this is set to "true", the module must be executed with root permissions.
If the module has to perform some action at system startup, use this entry to build the name of a function to call. if X-KDE-Init-Symbol is "bell", for example, the function "kcminit_bell" is called in the library indicated by X-KDE-Library.
The module loader will then show the module in greyed-out (disabled) state
with a warning until the "modify" button is pressed which allows running the
module in an root environment using kdesu and QXEmbed.


;X-KDE-Init
;NoDisplay
If the module has to perform some action at system startup, use this entry to
If this is set to true the module will not show up in System Settings or when viewed with kcmshell5. This is useful when you need to do something at startup using X-KDE-Init but don't want the module to show up in System Settings.
build the name of a function to call. if X-KDE-Init is "bell", for example,
the function "init_bell" is called in the library indicated by X-KDE-Library.


;X-KDE-Test-Module
You can also make the value of this key depend on the output of a program, using the "[$e]" key suffix. For example:
If the module has to perform some action at system startup, use this entry to
build the name of a function to call. if X-KDE-Init is "bell", for example,
the function "init_bell" is called in the library indicated by X-KDE-Library.


;NoDisplay
<pre>
If this is set to true the module will not show up in System Settings or when viewed
Hidden[$e]=$(if test -e /dev/js*; then echo "false"; else echo "true"; fi)
with kcmshell4. This is useful when you need to do something at startup using X-KDE-Init
</pre>
but don't want the module to show up in System Settings.
 
This example executes the given code in a shell and uses the stdout output for the Hidden value (so it's either Hidden=true or Hidden=false).


==Example CMakeLists.txt==
==Example CMakeLists.txt==
Line 199: Line 219:
)
)
</syntaxhighlight>
</syntaxhighlight>
Please note that your library name should only contain letters (upper and lowercase), numbers and underscores ("[A-Z][a-z][0-9]_"), because this name will be used internally as a dbus object. So "kcm_foo" is fine while "kcm-foo" is not.


==What else do I need?==
==What else do I need?==
Line 204: Line 226:
There are a number of additional things for convenience.
There are a number of additional things for convenience.


===kcmshell4===
===kcmshell5===
 
Consider you want to run a module standalone. Call "kcmshell4 module". For
example, to get the font and the desktop color settings, use:


    kcmshell4 fonts colors
You can run one or several modules independently with "kcmshell5 [module_name]". For example, to get the font and the desktop color settings, use "kcmshell5 fonts colors".


===KCMultiDialog===
To get a list of the available modules, use "kcmshell5 --list".


Sometimes, you may want to reuse your KCModule inside an application. There
=== KCMultiDialog ===
are two ways to accomplish this:
Sometimes, you may want to reuse your KCModule inside an application. There are two ways to accomplish this:


The first option is to simply fork and call "kcmshell4 foo".
The first option is to simply fork and call <syntaxhighlight lang="shell" inline>kcmshell5 foo</syntaxhighlight>.


The second option is to use {{class|KCMultiDialog}}. This is a simple dialog
The second option is to use {{Class|KCMultiDialog|kcmutils}}. This is a simple dialog which can show an arbitrary number of modules in a normal {{Class|KMessageDialog|kwidgetsaddons}}. This approach gives you finer control than starting kcmshell5 in a separate process.
which can show an arbitrary number of modules in a normal {{class|KDialog}}.
This approach gives you finer control to the behavior and results than starting
kcmshell4 in a separate process.


Since your module is a simple library, you can just link to it anyway.
Since your module is a simple library, you can just link to it anyway.
Line 232: Line 248:
==Debugging your module==
==Debugging your module==


You can attach gdb, valgrind or whatever to "kcmshell4 [yourmodule]" to track
You can attach gdb, valgrind or whatever to "kcmshell5 [yourmodule]" to track
down leaks or crashes. If you need to trace it down inside System Settings, make sure
down leaks or crashes. If you need to trace it down inside System Settings, make sure
you pass --nofork to System Settings on startup.
you pass --nofork to System Settings on startup.


You really want to use kcmshell4 for debugging as long as your debugging does
You really want to use kcmshell5 for debugging as long as your debugging does
not involve debugging bad interaction with the System Settings framework itself.
not involve debugging bad interaction with the System Settings framework itself.


Line 243: Line 259:
== About this howto ==
== About this howto ==


This howto has been imported from http://websvn.kde.org/trunk/www/sites/developer/documentation/other/kcm_howto.html?view=markup and updated to KDE4 by Aurélien Gâteau <[email protected]>.
This howto has been imported from http://websvn.kde.org/trunk/www/sites/developer/documentation/other/kcm_howto.html?view=markup and refreshed for KDE4 by Aurélien Gâteau <[email protected]>.


Original copyright header:
Original copyright header:

Latest revision as of 14:07, 5 January 2021

Warning
This page needs a review and probably holds information that needs to be fixed.

Parts to be reviewed:

Port to KF5
KCM HowTo
Tutorial Series   Plugins and KParts
Previous  
What's Next  
Further Reading   KCModule Class Reference

Introduction

This howto describes how to write KConfig Modules (KCMs from now on). These KCM can appear in System Settings or in the configuration dialog of individual applications.

A KCM is made of two elements:

  • A shared library
  • A desktop file

The shared library

Implementing a KCM is done by:

  1. Subclassing the KCModule class. In this documentation we assume the class inheriting from KCModule is named FooKcm.
  2. Exporting the module so that System Settings or kcmshell5 can find it.

The prefered way to export the module is through KPluginFactory. Here is how to do it:

    #include <KPluginFactory>

    K_PLUGIN_FACTORY(FooKcmFactory, registerPlugin<FooKcm>();)
    K_EXPORT_PLUGIN(FooKcmFactory("kcm_foo" /* kcm name */, "kcm_foo" /* catalog name */))

If you get errors, make sure the constructor signature of your derived class matches with the signature of KCModule constructor (the QVariantList argument matters).

If the name of your module is "foo", the name of the library should be "kcm_foo.so". It should be installed into $KDEDIR/lib/kde4.

Exporting more than one module

If you need to export more than one module per library, you have to declare them another way: you must create C functions named "create_${kcm_name}". For example if your module exposes two KCMs named Foo1 and Foo2, the "create_" functions would look like this:

    extern "C"
    {
        KCModule *create_foo1(QWidget *parent, const char *name)
        {
            return new Foo1Kcm(parent, name);
        };
        KCModule *create_foo2(QWidget *parent, const char *name)
        {
            return new Foo2Kcm(parent, name);
        };
    }

Additionally, you will need to add "X-KDE-FactoryName" keys to your desktop file. (see below)

Initializing on startup

It is possible to get code from the KCM to be run at startup by kcminit.

To do so you must declare a function named "kcminit_${module}", like this:

    extern "C"
    {
        KDEEXPORT void kcminit_foo()
        {
            // Do initialization here
        };
    }

You must also add a "X-KDE-Init-Symbol" key to your desktop file. (see below)

The desktop file

To declare a KCModule's existence a desktop file must be installed in the proper place.

Desktop files are defined in the desktop file specification.

Mandatory keys

A KCM desktop file must contains the following keys:

Type

Should be "Service".

X-KDE-ServiceTypes

Should be "KCModule" for most KCM. If you want to use the kcminit feature it should be "KCModule,KCModuleInit".

Icon

Specifies the icon for the module.

Exec

Should be "kcmshell5 foo".

Name

This will be used by System Settings as your KCM label.

Comment

This text shows up in the title area in System Settings. If the module is not grouped with other modules it will also be used as a tooltip in the KCM list view.

Categories

Should contain at least "Qt;KDE;X-KDE-settings-system;".

X-KDE-ParentApp

Set this to "kcontrol" if you want your KCM to show up in System Settings.

The application you put in this key determines in what situations your KCM will show. It is crucial to select a correct ParentApp, otherwise the KCM will show up in unnecessary places.

X-KDE-System-Settings-Parent-Category

Defines where the KCM will appear in System Settings.

Possible values at the time of this writing are:

  • settings-lost-and-found
  • settings-hardware
  • settings-network-and-connectivity
  • settings-system-administration
  • settings-application-appearance-and-behavior
  • settings-workspace-appearance-and-behavior

You can get a list of possible categories with this command, which lists all toplevel categories:

ktraderclient --servicetype SystemSettingsCategory --constraint "[X-KDE-System-Settings-Parent-Category] == ''" | grep DesktopEntryName

Just do not use the "settings-lost-and-found" entry.

X-KDE-Keywords

A comma-separated list containing words the search functionality should trigger on.

X-KDE-Library

This is the name of the library, without the "kcm_" prefix. In our example, it should be "foo".

Optional keys

Additionally the KCM desktop file may contains the following keys:

X-KDE-FactoryName

This entry can be used to set the name of the factory function in the library. If you only have one KCModule in a library this key is not needed. If you have several KCMs in one library you will need a desktop file for each KCM.

For example, if you have a library named: kcm_frog.so with two modules, named "kermit" and "quak", kcm_kermit.desktop would contain:

X-KDE-Library=frog
X-KDE-FactoryName=kermit

and "kcm_quak.desktop" would contain:

X-KDE-Library=frog
X-KDE-FactoryName=quak

The module loader would then call the "create_kermit" and "create_quak" functions respectively.

X-KDE-Init-Symbol

If the module has to perform some action at system startup, use this entry to build the name of a function to call. if X-KDE-Init-Symbol is "bell", for example, the function "kcminit_bell" is called in the library indicated by X-KDE-Library.

NoDisplay

If this is set to true the module will not show up in System Settings or when viewed with kcmshell5. This is useful when you need to do something at startup using X-KDE-Init but don't want the module to show up in System Settings.

You can also make the value of this key depend on the output of a program, using the "[$e]" key suffix. For example:

Hidden[$e]=$(if test -e /dev/js*; then echo "false"; else echo "true"; fi)

This example executes the given code in a shell and uses the stdout output for the Hidden value (so it's either Hidden=true or Hidden=false).

Example CMakeLists.txt

Here is a minimal CMakeLists.txt which builds and installs the shared library and the desktop files at the right places:

find_package(KDE4 REQUIRED)

include(KDE4Defaults)
include(MacroLibrary)

set(FOO_SRCS
    foo.cpp
    # Other sources go there
)

kde4_add_plugin(kcm_foo ${FOO_SRCS})

target_link_libraries(kcm_foo
    ${KDE4_KDEUI_LIBS}
    # Other necessary libraries go there
)

install(TARGETS kcm_foo
    DESTINATION ${PLUGIN_INSTALL_DIR}
)

install(FILES kcm_foo.desktop
    DESTINATION ${SERVICES_INSTALL_DIR}
)

Please note that your library name should only contain letters (upper and lowercase), numbers and underscores ("[A-Z][a-z][0-9]_"), because this name will be used internally as a dbus object. So "kcm_foo" is fine while "kcm-foo" is not.

What else do I need?

There are a number of additional things for convenience.

kcmshell5

You can run one or several modules independently with "kcmshell5 [module_name]". For example, to get the font and the desktop color settings, use "kcmshell5 fonts colors".

To get a list of the available modules, use "kcmshell5 --list".

KCMultiDialog

Sometimes, you may want to reuse your KCModule inside an application. There are two ways to accomplish this:

The first option is to simply fork and call kcmshell5 foo.

The second option is to use KCMultiDialog. This is a simple dialog which can show an arbitrary number of modules in a normal KMessageDialog. This approach gives you finer control than starting kcmshell5 in a separate process.

Since your module is a simple library, you can just link to it anyway.

KCModuleContainer

The class KCModuleContainer allows great flexibility to handle modules. The API docs explains its usage the best.

Debugging your module

You can attach gdb, valgrind or whatever to "kcmshell5 [yourmodule]" to track down leaks or crashes. If you need to trace it down inside System Settings, make sure you pass --nofork to System Settings on startup.

You really want to use kcmshell5 for debugging as long as your debugging does not involve debugging bad interaction with the System Settings framework itself.


About this howto

This howto has been imported from http://websvn.kde.org/trunk/www/sites/developer/documentation/other/kcm_howto.html?view=markup and refreshed for KDE4 by Aurélien Gâteau <[email protected]>.

Original copyright header:

Copyright (C) 2003 Daniel Molkentin <[email protected]>
Copyright (C) 2004 Frans Englich <[email protected]>

Permission is granted to copy, distribute and/or modify this document under the
terms of the GNU Free Documentation License, Version 1.2 or any later version
published by the Free Software Foundation; with no Invariant Sections, no
Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included
in the section entitled "GNU Free Documentation License".