|
|
|
How to implement DCOP communication between two applications so that
|
|
|
|
1) it works when the applications are standalone (separate processes)
|
|
|
|
2) it works when the applications are loaded as parts, embedded into kontact
|
|
|
|
3) it behaves properly when a separate process exits/crashes.
|
|
|
|
|
|
|
|
In the part
|
|
|
|
===========
|
|
|
|
Let's say that part 'A' wants to use the interface "Foo", via DCOP.
|
|
|
|
(where Foo is usually a generic name, e.g. Calendar, Mailer, AlarmDaemon, etc.)
|
|
|
|
The services which implement this interface are associated with the service type
|
|
|
|
"DCOP/Foo".
|
|
|
|
|
|
|
|
One of those services is application 'B', which implements "Foo" - note that
|
|
|
|
'B' should make sure that the "Foo" DCOP interface is available both when
|
|
|
|
'B' is used as standalone process and when 'B' is only loaded as a part.
|
|
|
|
(This means that if the app doesn't use its own part, then both should implement
|
|
|
|
"Foo", like kaddressbook does. Of course it's simpler if the app uses its own part :)
|
|
|
|
|
|
|
|
Here are some code snippets that must go into the part (A) that wants to use "Foo":
|
|
|
|
|
|
|
|
* Constructor:
|
|
|
|
m_foo_stub = 0L;
|
|
|
|
kapp->dcopClient()->setNotifications( true );
|
|
|
|
connect( kapp->dcopClient(), TQ_SIGNAL( applicationRemoved( const QCString&)),
|
|
|
|
this, TQ_SLOT( unregisteredFromDCOP( const QCString& )) );
|
|
|
|
|
|
|
|
* Destructor:
|
|
|
|
kapp->dcopClient()->setNotifications( false );
|
|
|
|
delete m_foo_stub;
|
|
|
|
|
|
|
|
[Note that setNotifications() is implemented with a refcount, this is the
|
|
|
|
correct way to do it and it won't mess up other parts]
|
|
|
|
|
|
|
|
* bool connectToFoo() method, which uses KDCOPServiceStarter::self()->findServiceFor("DCOP/Foo").
|
|
|
|
See test part for details (plugins/test/test_part.cpp).
|
|
|
|
|
|
|
|
* unregisteredFromDCOP( const QCString& appId ) slot, which will be called when
|
|
|
|
the process implementing Foo exits. The method simply does:
|
|
|
|
if ( m_foo_stub && m_foo_stub->app() == appId )
|
|
|
|
{
|
|
|
|
delete m_foo_stub;
|
|
|
|
m_foo_stub = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
* Now you can finally use the foo dcop interface. First you need to connect
|
|
|
|
to it:
|
|
|
|
if ( !connectToFoo() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
Then you can use m_foo_stub to call the DCOP methods.
|
|
|
|
In case of critical methods, where you want to make 100% sure that the DCOP
|
|
|
|
call was correctly done (e.g. the remote app didn't crash during the call),
|
|
|
|
you can use if ( !m_foo_stub->ok() ).
|
|
|
|
|
|
|
|
In the kontact plugin
|
|
|
|
=====================
|
|
|
|
* Don't use dcopClient() until the part is loaded
|
|
|
|
* After loading the part, you might want to create a DCOP stub to use some
|
|
|
|
of its methods (do both in a loadPart() method, e.g.).
|
|
|
|
* Implement createDCOPInterface( const TQString& serviceType ), to
|
|
|
|
load the part if the serviceType is one provided by it.
|
|
|
|
|
|
|
|
See KAddressbookPlugin (plugins/kaddressbook/*) for a working example.
|
|
|
|
|
|
|
|
Don't forget to
|
|
|
|
===============
|
|
|
|
* Define the service type, using a "Type=ServiceType" .desktop file,
|
|
|
|
with "X-TDE-ServiceType=DCOP/Foo".
|
|
|
|
See e.g. tdepim/kaddressbook/dcopaddressbook.desktop
|
|
|
|
|
|
|
|
* Add DCOP/Foo to the application's ServiceTypes list, in its .desktop file
|
|
|
|
See e.g. tdepim/kaddressbook/kaddressbook.desktop
|
|
|
|
* Make sure that X-DCOP-ServiceType and X-DCOP-ServiceName are specified too.
|
|
|
|
|
|
|
|
Designing DCOP interfaces
|
|
|
|
=========================
|
|
|
|
Porting the kroupware signals/slots to DCOP requires some changes.
|
|
|
|
For instance any non-const reference (such as those used for returning
|
|
|
|
values to the caller) has to be changed. If there is more than one
|
|
|
|
value to be returned, you need to
|
|
|
|
* define a structure containing all the returned values
|
|
|
|
* define QDataStream << and >> operators for that structure.
|
|
|
|
|
|
|
|
$Id$
|