The KDE Control Center
======================


The KDE Control Center is a central application that allows a 
user to:

a) change user specific settings
b) change KDE specific system settings
c) change system settings

The functionality is provided by a great number of "modules" 
that are embedded into a framework application called "kcontrol".


How to write a control center module(kcm)?
-------------------------------------

The mechanism to implement kcontrol modules changed quite a bit since 
KDE 2.0. In KDE 1.x the modules have been implemented as separate
processes that were swallowed into the control center. This had several
advantages, as well as disadvantages:

+ modules could run standalone
+ broken modules (segfaulting) left the framework untouched
- focus handling was hard to achive
- layout management was a pain
- communication between modules and framework was inefficient

To overcome the problems, modules from KDE 2.0 on are implemented as 
simple shared libraries that are loaded, at runtime, into the process
of the frame application. This solves all of the disadvantages.
To allow modules to run "standalone", there is a wrapper application
"kcmshell". What is left is the problem of segfaulting modules; the
solution is simple: don't let your modules segfault! :-)


Now to the practical side of things: Modules have to inherit from the
class KCModule, defined in kcmodule.h, which is part of kdeui.
This class defines some important functions that are used in the
communication between framework and module:

virtual void load();

This method is invoked whenever the module should read its configuration
(most of the times from a config file) and update the user interface.
This happens when the user clicks the "Reset" button in the control
center, to undo all of his changes and restore the currently valid
settings. NOTE that this is not called after the modules is loaded,
so you probably want to call this method in the constructor.

virtual void save();

You might have guessed it: this function gets called when the user
wants to save the settings in the user interface, updating the 
config files or wherever the configuration is stored.
The method is called when the user clicks "Apply" or "Ok".

virtual void defaults();

This function is called to set the settings in the module to sensible
default values. It gets called when hitting the "Default" button.
The default values should probably be the same as the ones the 
application uses when started without a config file.

int buttons();

The control center calls this function to decide which buttons should
be displayed. For example, it does not make sense to display an "Apply"
button for one of the information modules. The value returned can
be set by modules using setButtons. E.g.

setButtons(KCModule::Ok|KCModule::Help);

will make sure that only the "Ok" and the "Help" button is enabled.


There is also a signal used by the modules:

void changed(bool state);

This signal should be emitted whenever the state of the modules changes.
"state" is true, if the contents of the modules differ from the ones in
the current configuration, "false" otherwise. For example, if the user
changes a value, you emit "changed(true)". When the user reloads the
systems settings, emit "changed(false)". The control center uses
this signal to keep track about unsaved changes in certain modules.


How to make a module available?
-------------------------------

Ok, now that you have implemented your class with the module, you
must make sure it can be accessed from the control center. 

To achieve this, the preferred way since KDE 3.0 is to simply use 
KGenericFactory. Don't forget to #include <kgenericfactory.h>!

typedef KGenericFactory<MyKCModule, QWidget> KDEDFactory;
K_EXPORT_COMPONENT_FACTORY( kcm_xyz, KDEDFactory( "kcmxyz" ) );

If you get errors, make sure that the constructor of your derived class
equals the one of the KCModule baseclass (yes, the QStringList argument
matters).

If you need to export more than one module per library, you have to use the 
old loader. That is, you need to create a function like this:

extern "C"
{
  KCModule *create_xyz(QWidget *parent, const char *name)
  {
    return new XYZ(parent, name); // XYZ inherits from KCModule
  };
}

This function and the implementation of the module is then compiled
as a shared library. If the name of your modules is 'xyz', the
name of the library should be

kcm_xyz(.la|.so)

and should be installed into $KDEDIR/lib/kde3. (Ok, beat me for the KDEDIR, 
but you all know what I mean, don't you? :)

Use "kde_module_LTLIBRARIES = kcm_xyz.la" for that in your Makefile.am.
Don't call it libkcm_xyz as that is deprecated since KDE 3.0.



Initialize things on startup
----------------------------

If your module needs to initialize things on startup, you must have a 
construct like:

extern "C"
{
  KCModule *init_xyz(QWidget *parent, const char *name)
  {
    // to startup stuff here
  };
}

Don't forget to add X-KDE-Init to your desktop file! (see next chapter)


The .desktop entry
------------------

To make the control center find the module, it needs a .desktop
entry. This has to be placed under

$KDEDIR/applnk/Settings/...

so put it in kdebase/applnk/Settings... to have it installed.

Just as the old control center modules. There are a number of special
entries in the .desktop file for the modules:

X-KDE-ModuleType
	
	If the value if this entry is "Library", the module is
	assumed to be in a shared library. All KDE 2.0 modules should
	be of this type, it is only here to keep some kind of
	upward compatibility with the old style modules.

X-KDE-Library

	This is the name of the library, without the kcm_ prefix.
	So in the example, the library name would be "xyz".

X-KDE-FactoryName

	This entry can be used to set the name of the factory
  	function in the library. Usually, this is the same as
	the Library, but if you want to have more than
	one module in one library, you need this entry.

	For example, if you have a library named

	kcm_frog.la

	with two modules, named "kermit" and "quak", you would
	have 

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

	in one of the .desktop files, and in the other

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

	The control center would then call the "create_kermit" and
	"create_quak" functions respectively.


X-KDE-RootOnly

	If this is set to "true", the module must be executed
	with root permissions. The control center 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

	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
	If this is set to true the module will not show up in
	kcontrol or when viewed 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.


Don't forget the usual entries :

Type=Application
Icon=...
Exec=kcmshell dir/file


What else do I need?
--------------------

There are a number of additional things for convenience. 

- kcmshell

Consider you want to run a module standalone, without the control
center. You can no longer call the module, as it is a library
now. Instead, call "kcmshell module". For example, to get the
font and the desktop color settings, use

  kcmshell fonts colors

- multiple instances of kcontrol

With the new control center, it is no longer possible to have multiple
instances in the control center.

- KCDialog

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

a) call "kcmshell modules"

to run the module as a separate program.

b) use "KCMultiDialog" (in kdelibs/kutils)

This is a simple dialog that can show an abitrary number of modules 
in a normal KDialogBase.

The advantage is that you can control the behaviour and the results 
much easier that with a separate process. And as your module is a 
simple library, you can just link to it anyway. 

Debugging your module
---------------------

You can attach gdb, valgrind or whatever to kcmshell <yourmodule> to track 
down leaks or crashes. If you need to trace it down inside kcontrol, make
sure you pass --nofork to kontrol on startup. Anyway, you really want to use 
kcmshell for debugging as long as your debugging does not involve debugging bad
interaction with the kcontrol framework itself.

More questions?
---------------

Ask Daniel Molkentin <molkentin@kde.org>
