Creating a DCOP Interface

Richard Moore, rich@kde.org

Introduction

This example provides a DCOP interface to a simple KDE application, and illustrates how it can be used. Adding the interface is easy, the example defines a number of methods of different types, and as you'll see all these methods can be quickly used via DCOP. You can download the full source code for the example.

The Demo Application

The application we're going to work with is very simple, it stores a couple of variables (an int and a QString) which both have accessor methods, and provides a few other methods to print output to a text view. The header file for the example is shown below and as you can see the only reference to DCOP comes in the first line, nothing else is needed here. As you can see the DCOPDemoWidget extends QVBox (though this could have been any QWidget subclass), and also extends the DCOPDemoIface class. Note that DCOPDemoIface is a virtual base class for the demo widget, there's no need to explain the details of the implications of this but it is important to make sure you don't forget (as I did when I first tried to get it to work!). The rest of the header file just defines the demo class as normal.

00 class DCOPDemoWidget : public QVBox, virtual public DCOPDemoIface
01 {
02     Q_OBJECT
03 
04 public:
05     DCOPDemoWidget();
06     ~DCOPDemoWidget();
07 
08     QString strVal() const { return str; }
09     int numVal() const { return num; }
11 
12 public slots:
13     void setNumVal( int num );
14     void setStrVal( const QString &str );
15 
16     void output( const QString &msg );
17     void dump();
18 
19 private:
20     void createGUI();
21 
22     QMultiLineEdit *log;
23     QPushButton *run;
24 
25     QString str;
26     int num;
27 };

Now that we've seen the header file, we can take a look at the implementation of the DCOPDemoWidget class, which is of course, rather longer than the header file. The vast majority of the code below simply provides us with an example widget to show off our DCOP interface, as before the amount of code that is DCOP related is tiny - in fact it is all in the first ten lines. The first thing to look at is the initialiser at line 2, it initialises the DCOPObject base class, and specifies the name of our interface which will be 'DCOPDemoIface'. The only other DCOP related part of the implementation is the code that registers the application with the DCOP server, this can be found at lines 6-10. These lines check to see if the app is already registered, and if not register it specifying the name as 'dcopifacedemo'. The final step (line 9) makes tells DCOP that the default object offered to clients should be our DCOP interface, which we obtain by calling the objId() method we inherited from DCOPObject.

00 DCOPDemoWidget::DCOPDemoWidget()
01     : QVBox( 0, "DCOPDemoWidget" ),
02       DCOPObject( "DCOPDemoIface" )
03 {
04     createGUI();
05 
06     // Register with DCOP
07     if ( !kapp->dcopClient()->isRegistered() ) {
08         kapp->dcopClient()->registerAs( "dcopifacedemo" );
09         kapp->dcopClient()->setDefaultObject( objId() );
10     }
11 }
12 
13 DCOPDemoWidget::~DCOPDemoWidget()
14 {
15 }
16 
17 void DCOPDemoWidget::setNumVal( int num )
18 {
19     output( QString( "setNumVal( \"%1\" )" ).arg( num ) );
20     this->num = num;
21 }
22 
23 void DCOPDemoWidget::setStrVal( const QString &str )
24 {
25     output( QString( "setStrVal( \"%1\" )" ).arg( str ) );
26     this->str = str;
27 }
28 
29 
30 void DCOPDemoWidget::dump()
31 {
32     output( QString( "String: \"%1\", Number: \"%2\"" ).arg( str ).arg( num ) );
33 }
34 
35 void DCOPDemoWidget::createGUI()
36 {
37     setSpacing( KDialog::spacingHint() );
38     setMargin( KDialog::marginHint() );
39 
40     (void) new QLabel( "<font size=\"+2\"><b>DCOP Interface Demo</b></font>",
41 		       this, "Title" );
42 
43     log = new QMultiLineEdit( this, "LogView" );
44     log->setReadOnly( true );
45 
46     run = new QPushButton( "&Dump Values", this, "DumpButton" );
47     connect( run, SIGNAL( clicked() ), SLOT( dump() ) );
48 }
49 
50 void DCOPDemoWidget::output( const QString &msg )
51 {
52     log->insertLine( msg );
53     log->setCursorPosition( log->numLines() - 1, 0 );
54 }

The DCOP Interface

The final thing to look at is the DCOP interface itself, this is included below and as you can see it looks similar to the class declaration. The interface definition includes two special macros K_DCOP, and k_dcop: which are similar to the Q_OBJECT macro used by moc. The rest of the code is normal C++ and defines the methods we want our interface to contain which must be pure-virtual functions (the implementation is provided by the application as we saw above).

00 class DCOPDemoIface : virtual public DCOPObject
01 {
02     K_DCOP
03     k_dcop:
04 
05     virtual QString strVal() const = 0;
06     virtual int numVal() const = 0;
07 
08     virtual void setNumVal( int num ) = 0;
09     virtual void setStrVal( const QString &str ) = 0;
10 
11     virtual void output( const QString &msg ) = 0;
12     virtual void dump() = 0;
13 };

Believe it or not, that's all we have to do! If you compile the example you'll see that you now have a fully functioning DCOP interface - easy wasn't it.

Building The Code

Building our example is easy, as you can see from the Makefile.am below. The only thing that differs from a basic KDE application is at the end of line 1, where the dcopdemoiface.skel is listed. The skel file is created automatically by dcopidl when it processes our DCOP interface definition.

00 bin_PROGRAMS = dcopifacedemo
01 dcopifacedemo_SOURCES = dcopdemowidget.cpp main.cpp dcopdemoiface.skel
02 dcopifacedemo_LDADD   =  $(LIB_QT) $(LIB_KDECORE) $(LIB_KDEUI) $(LIBSOCKET)
03 
04 # set the include path for X, qt and KDE
05 INCLUDES= $(all_includes)
06 
07 METASOURCES = AUTO
08 
09 # the library search path. 
10 dcopifacedemo_LDFLAGS = $(all_libraries) $(KDE_RPATH)

The Results

The screenshot below shows kdcop viewing the DCOP interface of the example - as you can see all of the methods we specified in DCOPDemoIface are available, as is the built in qt interface.

DCOP Browser

Here is a session log demonstrating the DCOP interface using the command line dcop utility.

rich@pegasus$ ./dcopifacedemo &
rich@pegasus$ dcop
kwin
kicker
extension_proxy-8719
kwrited
kded
knotify
dcopifacedemo-18247
klauncher
khotkeys
kdesktop
klipper
ksmserver
rich@pegasus$ dcop dcopifacedemo-18247 DCOPDemoIface
QCStringList interfaces()
QCStringList functions()
QString strVal()
int numVal()
void setNumVal(int num)
void setStrVal(QString str)
void output(QString msg)
void dump()
rich@pegasus$ dcop dcopifacedemo-18247 DCOPDemoIface  dump
rich@pegasus$ dcop dcopifacedemo-18247 DCOPDemoIface  setStrVal 'Hello DCOP'
rich@pegasus$ dcop dcopifacedemo-18247 DCOPDemoIface  strVal
Hello DCOP
rich@pegasus$ dcop dcopifacedemo-18247 DCOPDemoIface  dump

Below you can see a screenshot of our demo application immediately after we set the call to setStrVal.

DCOP Interface Demo

Conclusion

Hopefully you've now seen just how easy it is to add DCOP support to your application, and you're now rushing off to give it a try.