Simon Hausmann <hausmann@kde.org>
v1.0 26, June 1999
This documentation describes the KDE Daemon, the services it provides and how to use it. So if you're dealing with CORBA servers in the KDE or if you're interested in a smart way of accessing KService data in your application then you might want to read this and use kded
The KDE Daemon, herein simply named kded, is a central daemon in the KDE Desktop Environment. It provides three services:
Before we can use any of kded's services, we have to know something about it's "position" in the KDE and the way it itself and the services can be accessed.
As kded uses CORBA to communicate with it's clients, your application (as client), has to
The first two points are fixed for all clients, the third one depends on the specific client. In general you have to choices:
CORBA::ORB_ptr orb = CORBA::ORB_init( argc, argv, "mico-local-orb" );Please note that when using this construct or similar ones, your application is not able to act as CORBA server if you are using KDE/Qt classes at the same time. This is due to the fact that the ORB needs it's own event loop, beside the main Qt event loop. Currently only KOMApplication, as part of the KDE Object Model, implements the needed functionality to combine both event loops and thus making KDE apps able to serve CORBA Objects.
Although kded uses CORBA extensively, the API is kept simple and free from complicated CORBA stuff. In fact when talking about kded and it's API not the kded server is meant but the KDE Daemon library. This library contains the interface to the server (for the clients) as well as the whole server functionality. The reason for this is based on the idea that an application using kded should not be forced to rely on an existing kded server binary nor a running server at all. The following three situations may exist when a client app gets started:
To sum it up: libkded will always make sure that the services of kded are available for your client application, no matter in what alien environment the app is running :-) . And, although you don't have to care about this, you can optionally control this behaviour of libkded by adding one of the following three commandline arguments to your app:
Your actual interface to kded and it's services is the KdedInstance
class,
defined in kded_instance.h . So if you want to use kded (I guess that's why you're
reading this shit ;) ) then make sure to create one single instance
of it, preferably by adding the following line somewhere in the beginning of
your main()
:
KdedInstance( argc, argv, _a_reference_to_the_orb_here_ );If you're using KOMApplication as application object (make sure to create the instance before this line) , then you're fine by specifying
komapp_orb
as
reference to the ORB.
As there is always only one single instance of this class, you can simply access
it by the static self()
method of the class from anywhere you want. No
need to pass KdedInstance arguments all around in your program ;-) .
For further information about KdedInstance
you might want to read
kded_instance.h
, it's pretty good documented.
As already mentioned in the introduction, KTrader gives you access to the registry.
"Now what the hell is the registry?" you might ask. As this is just a documentation
about kded/libkded, I can only respond: "Please consult the documentation of/in
libkio
for more information" :-} . Just one thing about it here: KTrader loads
the whole and bloaty registry for you. Thanks to the magic of libkio
the loaded
registry will always be in sync with the "real" registry, the .desktop files in
the following standard directories (both types, the system wide and the user ones) :
Now over to KTrader and it's API. Similar to KdedInstance
there can
be only one single instance. The difference is that you don't have to care
about allocating it, just simply get a reference to the KTrader by calling
the ktrader()
method of KdedInstance
. And: don't
even think about deleting the returned reference! Just simply use it and be
happy with it :-) . (hey, kded is designed to be easy to use, no need for difficult
stuff...)
The KTrader API is even so simple that it contains only two methods ;-) . But
before I describe these methods you have to know something about the kind of
data KTrader returns. In simple words: You will always get a list of KService
objects. More detailed: The returned list is a QValueList
and the
entries are KSharedPtr
's (FIXME: will soon be renamed to QSharedPtr,
as it will become part of Qt.... AFAIK) to KService
objects. Please
read the corresponding Qt documentation about these two classes. The big advantage
of using these two template classes is that everything becomes easy for you
and that the memory consumption is kept at a minimum . You don't have to care
about pointers, freeing them and cleaning up the list, as long as you use
KTrader::ServicePtr
variables to hold the KService objects and as
long as you use KTrader::OfferList
to pass the list around in your
program. So: Remember to always use these two types when dealing with KTrader!
Now over to the two methods.
KTrader::listServices()
returns your a list of all available
services in the whole KDE. (no need for further explanations I think...)
KTrader::query()
is the key method of this beast. It performs a lookup
in the registry database, given your information about what you want to have.
The first argument is the name of the servicetype which all returned services
must implement. If you're unsure about the word "servicetype" , then you can
replace it with "mimetype" , for most, but not all, cases.
The second argument is an additional constraint expression, which has to be fulfilled by a service.
The third argument is a preference expression after which the returned services will be sorted. The value of the expression has to be numeric.
The syntax of these two expressions is equal with the language of the standard CORBA Trader (this is due to the fact that the parsing code is from the COS Trader of MICO) . The language is not very difficult and I don't want to bloat this documentation with further explanations about it. Please consult your CORBA literature for more information. Just one thing you have to know: Comparisons are always done with the properties of the KService object, which are the standard entries (Name, ServiceType, RepoIds, ...) plus the ones specified in the servicetype declaration and read by KService.
Well, after so much theoretical explanations it's time for some practical example code:
... //get a reference to the KTrader KTrader *trader = KdedInstance::self()->ktrader(); ... //will return a list of all services which implement the servicetype //named "text/plain" KTrader::OfferList offers = trader->query( "text/plain" ); ... //will return a list of all services which implement the servicetype //named "image/gif" and which have the AllowAsDefault property set true KTrader::OfferList offers = trader->query( "image/gif", "AllowAsDefault == TRUE" ); ... //will return KSpread ;-) KTrader::OfferList offers = trader->query( "KOfficeDocument", "(Exec == 'kspread') and (Path != '/opt/gnome/bin')" ); ... //will return a list of all services which implement the servicetype //named "BlahFoo" and which will be sorted (from lowest to highest) by //the value of the property "Price" , declared in the servicetype //declaration of BlahFoo. KTrader::OfferList offers = trader->query( "BlahFoo", QString::null, "min Price" );
Please note that KTrader, since it queries libkio
for services, will
always return services sorted by the user's preferences for the specific
servicetype. These preferences can be specified in the file "profilerc" .
This section requires to be familiar with libkio
and it is meant for everybody who
wants to use KRun in his application.
KRun requires a fully loaded registry in order to resolve mimetype <-> application
bindings. A fully loaded registry means that you need a KServiceTypeFactory
and
a KServiceFactory, which both load the appropriate KServiceType
KService
objects.
Now the KServiceType information doesn't need that much memory, but the KService
object really eat loooots of it. And isn't it kind of stupid to load this information
if this is already done by kded? Yes, it is ;-) .
What we would need is to make KRun query KTrader for KService data, instead of
directly using KServiceTypeProfile. Fortunately KRun is flexible enough for this,
we just need a re-implementation of the KServiceProvider, defined in krun.h
and used by KRun. Guess what, but KTrader provides you this re-implementation :-) .
Just have a look at the end of ktrader.h
.
To sum it up: The following line makes KRun query kded, in your application:
... //place this somewhere BEFORE the first usage of KRun, preferable somewhere //in main() KTraderServiceProvider serviceProvider; ...That's all, except that you must have a KdedInstance in order to be able to use it.
One often mentioned problem, when talking about applications which provide their services via CORBA, is how to start and access these services. Solutions like making apps write the IOR of an object somewhere into a file in the filesystem or similar approaches are just hacks ;-) . Better use KActivator, since it can automatically, on demand, start servers for you or use already running ones. This is accomplished with the help of the mediators for BOA/POA and the IMR (Implementation Repository), both provided by MICO. Fortunately you don't have to deal with IMR entries and the mediators.
Before you can use KActivator to start a server for you, you have to register the server's service. There are two possible ways, the last one is highly recommended though:
For the second point it's important that the .desktop file is available for KRegistry, by placing it in a directory which gets scanned by the registry. If your application has already a .desktop file in the applnk tree for example, then you're fine with adding the necessary fields in there. Otherwise the directory named "services" (either system-wide or user-local) is the best place for it. If you provide the CORBA service information this way, then KActivator will automatically detect it and register it automatically at the IMR. This means that it is immediately available for KActivator and thus to your client app. And since KRegistry is such a cool thing :-) , you can do all this even at run-time, when kded is running. Just place the .desktop file in one of the right directories for it and KActivator will update the IMR on-the-fly. The same applies obviously for just deleted or modified .desktop files, which will make KActivator adjust the IMR. Now you might get the idea why this is the preferred way :-)) .
Now that you know how to register CORBA services you will want to know how
to "access" it. activateService()
is your friend here. Simply pass
it the name of the service, the repository id of the server object and the
object's tag and it will return you a functional object reference. That's all :-)
Depending on the service's activation mode, KActivator will either return a reference to an already running server or it will start a new instance.
One note about the returned object reference: This is a virtual reference, which means that that server object is started when the first call is invoked on this reference, thus making your server get started "lazy", only on-demand. But that's just additional information, you don't have to deal and know about it at all. Just be happy with your functional object reference :-) .
Want some examples? Here we go:
This is how a .desktop file could look like, assuming that the commandline "--server" starts the app in CORBA server mode:
Name=MyApp Exec=fooblah CORBAExec=fooblah --server X-KDE-RepoIds=IDL:Foo/Blah:1.0#MyFoo X-KDE-ActivationMode=shared
If KActivator "gets" this file, it will register the service and then you're able to do something like this:
... KActivator *activator = KdedInstance::self()->kactivator(); ... CORBA::Object_var obj = activator->activateServer( "MyApp", "IDL:Foo/Blah:1.0", "MyFoo ); ...
The above example will either start a new fooblah instance or connect to a running one.
For further information please have a look at the examples in kdelibs/corba/tutorials/kded .
The example application there registers the server manually via registerService
.
Please note: The server has to be started by kded in order to make KActivator return a reference to a running one. Executing "fooblah" from somewhere else will not make KActivator use it. This is a problem for persistent servers like KDesktop for example. But there's a solution available, just read the next chapter about the KDE Naming Service :-) .
The KDE Naming Service, KNaming, is also a very simple service, but it's pretty useful and in some cases a very nice solution to make a CORBA client connect to a persistent CORBA server.
With KNaming you can bind a freely chooseable name to a CORBA object. And since kded is system (session) wide available, your object becomes available for any client which is able to connect to kded.
There's not much to explain here :-} , so I suggest having a look at the KNaming
API, in knaming.h
.
Example code can be, again, found in kdelibs/corba/tutorials/kded . Here's just a short real example situation:
Just think of KDesktop, that nice app providing your background desktop icons. It provides some functionality via CORBA, just have a look at kdesktop.idl to see what I'm talking about. Now the problem for KDesktop is: How can it provide this service to other apps in the system? Writing an IOR into some file is no clean solution IMHO, and using KActivator doesn't work because KDesktop does not get started by kded but by the startkde script on KDE startup. So we find a better way and make KDesktop register it's object at KNaming. This is done by the following lines:
... KNaming *knaming = KdedInstance::self()->knaming(); naming->bind( "KDesktop", kdesktop_object_here ); ...Well, I told you a lie ;) : KNaming does not really bind to "KDesktop" but instead to "IDL:KDesktopIf:1.0" , but since there's no naming convention for the naming I have choosen a more readable name, IMHO of course :-) (don't mind me David :] ) . I personally prefer human readable names ;) , in contrary to repository ids with tags.
Back to KNaming and KDesktop: Now any client application, kfmclient for example, can "connect" to KDesktop. Just like this:
.. KNaming *knaming = KdedInstance::self()->knaming(); ... CORBA::Object_var obj = knaming->resolve( "KDesktop" ); KDesktopIf_var kdesky = KDesktopIf::_narrow( obj ); kdesky->selectAll(); //let's confuse the user by selecting all icons ;-) ...