[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