1 ### Note: the dcop->dbus conversion of file isn't complete
4 How to implement DBus communication between two applications so that
5 1) it works when the applications are standalone (separate processes)
6 2) it works when the applications are loaded as parts, embedded into kontact
7 3) it behaves properly when a separate process exits/crashes.
11 Let's say that part 'A' wants to use the interface "Foo", via DBus.
12 (where Foo is usually a generic name, e.g. Calendar, Mailer, AlarmDaemon, etc.)
13 The services which implement this interface are associated with the service type
16 One of those services is application 'B', which implements "Foo" - note that
17 'B' should make sure that the "Foo" DBus interface is available both when
18 'B' is used as standalone process and when 'B' is only loaded as a part.
19 (This means that if the app doesn't use its own part, then both should implement
20 "Foo", like kaddressbook does. Of course it's simpler if the app uses its own part :)
22 Here are some code snippets that must go into the part (A) that wants to use "Foo":
26 // ### port to dbus: nameOwnerChanged
27 connect( kapp->dcopClient(), SIGNAL( applicationRemoved( const QCString&)),
28 this, SLOT( unregisteredFromDCOP( const QCString& )) );
33 [Note that setNotifications() is implemented with a refcount, this is the
34 correct way to do it and it won't mess up other parts]
36 * bool connectToFoo() method, which uses KDBusServiceStarter::self()->findServiceFor("DBus/Foo").
37 See test part for details (plugins/test/test_part.cpp).
39 * unregisteredFromDCOP( const QCString& appId ) slot, which will be called when
40 the process implementing Foo exits. The method simply does:
41 if ( m_foo_stub && m_foo_stub->app() == appId )
47 * Now you can finally use the foo DBus interface. First you need to connect
49 if ( !connectToFoo() )
52 Then you can use m_foo_stub to call the DBus methods.
53 In case of critical methods, where you want to make 100% sure that the DBus
54 call was correctly done (e.g. the remote app didn't crash during the call),
55 you can use if ( !m_foo_stub->ok() ).
59 * Don't use dcopClient() until the part is loaded ##
60 * After loading the part, you might want to create a DBus stub to use some
61 of its methods (do both in a loadPart() method, e.g.).
62 * Implement createDBusInterface( const QString& serviceType ), to
63 load the part if the serviceType is one provided by it.
65 See KAddressbookPlugin (plugins/kaddressbook/*) for a working example.
69 * Define the service type, using a "Type=ServiceType" .desktop file,
70 with "X-KDE-ServiceType=DBus/Foo".
71 See e.g. kdepim/kaddressbook/dcopaddressbook.desktop
73 * Add DBus/Foo to the application's ServiceTypes list, in its .desktop file
74 See e.g. kdepim/kaddressbook/kaddressbook.desktop
75 * Make sure that X-DBUS-StartupType (usually set to Unique)
76 and X-DBUS-ServiceName (usually set to org.kde.appname) are specified too.
78 Designing DBus interfaces
79 =========================
80 Porting the kroupware signals/slots to DBus requires some changes.
81 For instance any non-const reference (such as those used for returning
82 values to the caller) has to be changed. If there is more than one
83 value to be returned, you need to
84 * define a structure containing all the returned values
85 * define QDataStream << and >> operators for that structure.