[Kde-bindings] Using SMOKE with Qt2 style slots/signals

Richard Dale Richard_Dale at tipitina.demon.co.uk
Thu May 27 09:09:13 UTC 2004


I've been puzzling over how to implement slots and signals for SMOKE/qt2. I 
think invoking a signal will be similar to how it's done in SMOKE/qt3, but 
the problem is with invoking slots. 

In Qt2 QObject::metaObject() is still a virtual method so it's possible to 
override it and build a custom QMetaObject at runtime, instead of the static 
metaobject normally created by the moc. But inside the metaObject there is a 
table of pointers to functions (QMembers) against the slot or signal names. 
The QMember, name and receiver are used to construct a QConnection instance 
which becomes the target of the signal that is connected to it.

A slot declaration in a header:

public slots:
    void setValue( int );

Generates this code to set up an entry in the static MetaObject table:

    typedef void (LCDRange::*m1_t0)(int);
    typedef void (QObject::*om1_t0)(int);
    m1_t0 v1_0 = &LCDRange::setValue;
    om1_t0 ov1_0 = (om1_t0)v1_0;
	...
    slot_tbl[0].name = "setValue(int)";
    slot_tbl[0].ptr = (QMember)ov1_0;

The slot_tbl[0].ptr is then used to invoke the setValue() slot.

When the signal is emitted and the slot is invoked the function pointer inside 
the QConnection is used to call it. Unfortunately the QConnection instance 
isn't visible for the called slot (only the sending object), so the slot 
can't tell what it's name and arg types are. So if we wanted to add 'fake' 
functions pointers to a custom metaObject, which would actually end up 
calling a ruby or perl method, it isn't easy to tell the 'fake slot' what 
it's actual name is supposed to be.

Each slot or signal declared in ruby or perl would need to have it's own 
function pointer, and a dictionary used to look up the name of the slot and 
the class it belongs to. So how to implement a pool of general purpose slot 
handling function pointers?

I think like this:

class RubySlot : public QObject
{
public:
	void x1(...) 
	{
		va_list	ap;
		int		d;
		
		va_start(ap, this);
		d = va_arg(ap, int);
		va_end(ap);

		// Now call the real slot:
		printf("RubySlot::x1 d: %d\n", d);
		LCDRange * temp = (LCDRange*) this;
		temp->setValue(d);
		
	}
	void x2(...) 
	{
		va_list	ap;
		va_start(ap, this);
		va_end(ap);
	}
	// More fake slots from x3 to (say) x100
};

Each fake slot is a stdargs and so they are always type compatible with a 
QMember. They can be installed in a QMetaObject table like this:

    slot_tbl[0].name = "setValue(int)";
    slot_tbl[0].ptr = (QMember)&RubySlot::x1;

So instead of the normal LCDRange::setValue() slot being called, the 
RubySlot::x1 method is called. The x1() method in the example then calls the 
actual C++ setValue method, but it could just as easily call the ruby or perl 
equivalent instead after pushing the C++ args onto a Smoke::Stack first, and 
then marshalling.

Each slot or signal declared in the scripting language would use up a function 
pointer, so that would limit the maximum number of slots to 100, if they were 
x1 to x100. But maybe for Qt embedded that limit wouldn't matter as the 
programs wouldn't be that big.

-- Richard



More information about the Kde-bindings mailing list