[Kde-bindings] Implementing Ruby DCOP

Richard Dale Richard_Dale at tipitina.demon.co.uk
Thu Sep 25 14:00:32 UTC 2003


Ian Reinhart Geiser mentioned Ruby dcop on the kdecore list yesterday..

So I've been looking at how DCOP works, to see what needs to be done to make 
it work with KDE ruby. In C++ you make your dcop class a sub-class of 
DCOPObject, and add the K_DCOP macro in a similar manner to Q_OBJECt, and the 
methods after the 'k_dcop:' label can be called from outside the app.

class AddresseeHelper : public QObject, public DCOPObject
{
  K_DCOP
        
  public:
    static AddresseeHelper *self();
...
  k_dcop:
    ASYNC initSettings();

In Ruby I think it should look like this:

class AddresseeHelper < Qt::Object
    def AddresseeHelper.self()
    end
    ...

  k_dcop 'ASYNC initSettings()'

    def initSettings()
	.. do stuff
    end

The k_dcop contains a list of dcop slots, just like the current 'signals' and 
'slots' declarations in QtRuby. AddressHelper doesn't need to be a subclass 
of DCOPObject. When a new instance of AddressHelper is created, a associated 
RubyDCOPProxy C++ instance would be instanciated, with the ruby VALUE of the 
AddressHolder instance held as an instance variable. It would implement 
process(), functions() and interfaces() methods derived from the strings in 
the ruby 'k_dcop' statement.

The method is invoked in the process() virtual method overriden from 
DCOPObject, for example:

bool UIServer::process(const QCString &fun, const QByteArray &data, QCString& 
replyType, QByteArray &replyData)
{
    static QAsciiDict<int>* fdict = 0;
    if ( !fdict ) {
	fdict = new QAsciiDict<int>( UIServer_fhash, true, false );
	for ( int i = 0; UIServer_ftable[i][1]; i++ )
	    fdict->insert( UIServer_ftable[i][1],  new int( i ) );
    }
    int* fp = fdict->find( fun );
    switch ( fp?*fp:-1) {
    case 0: { // int newJob(QCString,bool)
	QCString arg0;
	bool arg1;
	QDataStream arg( data, IO_ReadOnly );
	arg >> arg0;
	arg >> arg1;
	replyType = UIServer_ftable[0][0]; 
	QDataStream _replyStream( replyData, IO_WriteOnly );
	_replyStream << newJob(arg0, arg1 );

Here the two args needed for the newJob(QCString,bool) call are extracted into 
arg0 and arg1 from the QDataStream 'data'. Then the method is called and the 
int return value is serialized into the _replyStream QDataStream.

In ruby I originally thought it would mean adding two extra actions to the 
marshalling 'VALUEtoDCOP', 'VALUEfromDCOP' or similar, in order to convert 
ruby values to a QDataStream and back. 

But the '<<' and '>>' methods are already in the Smoke runtime, so I think the 
best way is to go through each argument type string in the dcop method 
'QCString' and 'bool' above and call the appropriate '>>' method found via 
findMethod() from the Smoke runtime. Each argument value returned by '>>' 
would go into a ruby list, and the method 'newJob' called with the list.

VALUE argArray = rb_ary_new();
# Get each arg as a ruby value, and add to argArray.
...

rb_apply(self, rb_str_new2("newJob"), 2, argArray);

I think the api is already complete enough to invoke ruby signals, the args to 
be emitted have to be copied into a QDataStream before the signal is emitted:

   QByteArray params;
   QDataStream stream(params, IO_WriteOnly);
   stream << pid;
   kapp->dcopClient()->emitDCOPSignal("clientDied(pid_t)", params);

That looks as though it should almost work in ruby to me.

   params = ""
   stream = Qt::DataStream.new(params, IO_WriteOnly)
   stream << pid
   $kapp.dcopClient().emitDCOPSignal("clientDied(pid_t)", params)

That doesn't look as friendly as:

   $kapp.dcopClient().emitDCOPSignal( clientDied(pid) )

Which is more like emitting an ordinary signal. It needs more thought..

-- Richard


More information about the Kde-bindings mailing list