Development/Tutorials/KCM HowTo: Difference between revisions

    From KDE TechBase
    (Created page with "==Introduction== A KConfig Module is a small library with a @ref KCModule subclass containing code which builds and support a interface for configuration tasks. The module is th...")
     
    No edit summary
    (25 intermediate revisions by one other user not shown)
    Line 1: Line 1:
    {{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==


    A KConfig Module is a small library with a @ref KCModule subclass containing
    This howto describes how to write KConfig Modules (KCMs from now on). These KCM
    code which builds and support a interface for configuration tasks. The module
    can appear in System Settings or in the configuration dialog of individual applications.
    is then encapsulated in a parent application, for example kcmshell, System
    Settings or a KCMultiDialog.


    This HOWTO describes how to write KConfig Modules(KCMs from now on). This
    A KCM is made of two elements:
    technology was originally designed for KControl. Although KControl is the
    * A shared library
    application where the KCM tehnology is the most used, it is used in several
    * A desktop file
    other places as well, such as Kopete and Kontact. This HOWTO describes how to
    write config modules, regardless of where it will be used. KConfig Modules
    were originally called KControl Modules.


    ==Implementing==
    ==The shared library==


    Implementing a KCM is done by:
    Implementing a KCM is done by:
    # Subclassing the @ref 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 systemsettings or kcmshell can find it.
    # Exporting the module so that System Settings or kcmshell4 can find it.


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


    Line 26: 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>


    If you get errors, make sure that the constructor of your derived class equals
    If you get errors, make sure the constructor signature of your derived class matches
    the one of the KCModule baseclass (the QStringList argument matters).
    with the signature of {{class|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 use the
    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
    old loader. That is, you need to create a function like this:
    example if your module exposes two KCMs named Foo1 and Foo2, the
    "create_" functions would look like this:


    <syntaxhighlight lang="cpp">
    <syntaxhighlight lang="cpp">
         extern "C"
         extern "C"
         {
         {
          KCModule *create_foo(QWidget *parent, const char *name)
            KCModule *create_foo1(QWidget *parent, const char *name)
          {
            {
             return new FooKcm(parent, name);
                return new Foo1Kcm(parent, name);
          };
            };
             KCModule *create_foo2(QWidget *parent, const char *name)
            {
                return new Foo2Kcm(parent, name);
            };
         }
         }
    </syntaxhighlight>
    </syntaxhighlight>


    This function and the implementation of the module is then compiled as a
    Additionally, you will need to add "X-KDE-FactoryName" keys to your
    shared library. If the name of your modules is 'foo', the name of the library
    desktop file. (see below)
    should be kcm_foo.so and should be installed into $KDEDIR/lib/kde4 (see @ref kcm_install).


    ==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
          };
            };
         }
         }
    </syntaxhighlight>
    </syntaxhighlight>


    Don't forget to add X-KDE-Init 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==


    To declare a KCModule's existence a desktop file must be installed in the proper place (see @ref kcm_install).
    To declare a KCModule's existence a desktop file must be installed in the proper place.
     
    Desktop files are defined in the [http://www.freedesktop.org/Standards/desktop-entry-spec 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 "kcmshell4 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:
     
    <pre>
    ktraderclient --servicetype SystemSettingsCategory --constraint "[X-KDE-System-Settings-Parent-Category] == ''" | grep DesktopEntryName
    </pre>


    It could be a good idea to have a look at the [http://www.freedesktop.org/Standards/desktop-entry-spec desktop file specification].
    Just do not use the "settings-lost-and-found" entry.


    A KCM's .desktop file supports the following .desktop directives:
    ;X-KDE-Keywords
    A comma-separated list containing words the search functionality should trigger
    on.


    ;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,
    the library name would be "foo".
    it should be "foo".
     
    ===Optional keys===
    Additionally the KCM desktop file ''may'' contains the following keys:


    ;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 directive 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", you would have:
    For example, if you have a library named: kcm_frog.so with two modules, named "kermit" and "quak", kcm_kermit.desktop would contain:


    <syntaxhighlight lang="ini">
    <syntaxhighlight lang="ini">
    Line 91: Line 165:
    </syntaxhighlight>
    </syntaxhighlight>


    in one of the .desktop files, and in the other:
    and "kcm_quak.desktop" would contain:


    <syntaxhighlight lang="ini">
    <syntaxhighlight lang="ini">
    Line 100: 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-ParentApp
    The application you put in this entry determines in what situations it will
    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,
    otherwise the KCM will show up in unnecessary places.
     
    ;X-KDE-Init
    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.
     
    ;X-KDE-Test-Module
    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
    ;NoDisplay
    If this is set to true the module will not show up in kcontrol or when viewed
    If this is set to true the module will not show up in System Settings or when viewed with kcmshell4. 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.
    with kcmshell. This is usable when you need to do something at startup(X-KDE-
    Init etc.) but don't want the module to show up in kcontrol, eg. the module
    has no GUI.
     
    ;Name
    This is 'labels' for the KCMs and fill the nodes in the three view. Please see
    the KCM Guidelines on how to pick a good Name.
     
    ;Comment
    This directive shows up in the main area in KControl if you select a top node
    in the three view. See the same section as for Name in the KCM Guidelines for
    how to pick a good phrase.
     
    ;Categories
    This describes where the KCM should be put in KControl's navigation. It should
    look like "Categories=QT;KDE;X;" where X is the category. A list of available
    categories, as well as which one to choose is found in the KCM Guidelines.
     
    ;Icon
    Specifies the icon for the module.
     
    ;Exec
    Should say "Exec=kcmshell4 modulename".
     
    ;Type
    Should say "Type=Application".


    ;Keywords
    You can also make the value of this key depend on the output of a program, using the "[$e]" key suffix. For example:
    A semi colon separated list containing words/phrases search functionality
    should trigger on.


    To summarize, a valid KCM .desktop file ''must'' contain these directives:
    <pre>
    Hidden[$e]=$(if test -e /dev/js*; then echo "false"; else echo "true"; fi)
    </pre>


    * Name
    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).
    * Icon
    * Type=Application
    * Exec=kcmshell modulename
    * Categories=Qt;KDE;X; (replace X with your category)
    * Keywords
    * X-KDE-Library
    * X-KDE-ParentApp
    * Comment


    Additionally, a KCM .desktop file ''may'' contain:
    ==Example CMakeLists.txt==


    * X-KDE-Init
    Here is a minimal CMakeLists.txt which builds and installs the shared library and the
    * X-KDE-Test-Module
    desktop files at the right places:
    * NoDisplay
    * X-KDE-Root-Only
    * X-KDE-Factory-Name
    * DocPath
     
    Any other directives (except translations) can safely be removed, since they
    most likely are abundant or are left over's from old KDE versions. For example,
    X-ModuleType was relevant for KDE 2.0 but not in any new versions.
     
    ==Defining a CMakeLists.txt for the KCM==


    <syntaxhighlight lang="cmake">
    <syntaxhighlight lang="cmake">
    Line 188: Line 199:
    include(MacroLibrary)
    include(MacroLibrary)


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


    kde4_add_plugin(kcm_foo ${FOO_KCM_SRCS})
    kde4_add_plugin(kcm_foo ${FOO_SRCS})


    target_link_libraries(kcm_foo
    target_link_libraries(kcm_foo
    Line 215: Line 226:
    ===kcmshell4===
    ===kcmshell4===


    Consider you want to run a module standalone. Call "kcmshell4 module". For
    You can run one or several modules independently with "kcmshell4 [module_name]". For example, to get the font and the desktop color settings, use "kcmshell4 fonts colors".
    example, to get the font and the desktop color settings, use:


    kcmshell4 fonts colors
    To get a list of the available modules, use "kcmshell4 --list".


    ===KCMultiDialog===
    ===KCMultiDialog===
    Line 225: Line 235:
    are two ways to accomplish this:
    are two ways to accomplish this:


    First option is to use {{class|KCMultiDialog}}. This is a simple dialog that
    The first option is to simply fork and call "kcmshell4 foo".
    can show an abitrary number of modules in a normal {{class|KDialogBase}}. The
     
    advantage is that you can control the behaviour and the results much easier
    The second option is to use {{class|KCMultiDialog}}. This is a simple dialog
    that with a separate process. And as your module is a simple library, you can
    which can show an arbitrary number of modules in a normal {{class|KDialog}}.
    just link to it anyway.
    This approach gives you finer control than starting kcmshell4 in a separate process.


    Second option is to call "kcmshell4 modules".
    Since your module is a simple library, you can just link to it anyway.


    ===KCModuleContainer===
    ===KCModuleContainer===


    The class {{class|KCModuleContainer}} allows great flexibility with handling modules.
    The class {{class|KCModuleContainer}} allows great flexibility to handle modules.
    The API docs explains its usage the best.
    The API docs explains its usage the best.


    ===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 "kcmshell4 [yourmodule]" to track
    down leaks or crashes. If you need to trace it down inside systemsettings, make sure
    down leaks or crashes. If you need to trace it down inside System Settings, make sure
    you pass --nofork to systemsettings 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 kcmshell4 for debugging as long as your debugging does
    not involve debugging bad interaction with the systemsettings framework itself.
    not involve debugging bad interaction with the System Settings framework itself.


    ----
    ----
    Line 251: Line 261:
    == 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.
    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:

    Revision as of 17:46, 19 July 2012


    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 kcmshell4 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 "kcmshell4 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 kcmshell4. 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}
    )
    

    What else do I need?

    There are a number of additional things for convenience.

    kcmshell4

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

    To get a list of the available modules, use "kcmshell4 --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 "kcmshell4 foo".

    The second option is to use KCMultiDialog. This is a simple dialog which can show an arbitrary number of modules in a normal KDialog. This approach gives you finer control than starting kcmshell4 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 "kcmshell4 [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 kcmshell4 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".