diff options
Diffstat (limited to 'kontact/DESIGN.dcopinteraction')
-rw-r--r-- | kontact/DESIGN.dcopinteraction | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/kontact/DESIGN.dcopinteraction b/kontact/DESIGN.dcopinteraction new file mode 100644 index 000000000..f3b575987 --- /dev/null +++ b/kontact/DESIGN.dcopinteraction @@ -0,0 +1,84 @@ +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(), SIGNAL( applicationRemoved( const QCString&)), + this, 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 QString& 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-KDE-ServiceType=DCOP/Foo". +See e.g. kdepim/kaddressbook/dcopaddressbook.desktop + +* Add DCOP/Foo to the application's ServiceTypes list, in its .desktop file +See e.g. kdepim/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$ |