QMetaObject/GObject-introspection inter-operability progress
I've been hacking on deriving QMetaObjects for GObject-Introspection data as I described in a recent blog and am making good progress. I've now built a complete heirarchy of QMetaObjects from the gobject-introspection Clutter module which I've been using for testing.
I've checked the current code into playground/bindings/smoke_gobject so other people can play with it. It turns out that QMetaObject and the GObject Introspection models are pretty compatible. They both have single inheritance, properties, signals, runtime method calling (slots in Qt or or dynamic function invocation via ffi in G-I), enums and so on. So we need to add a dynamic runtime to call G-I methods as Qt slots or forward GObject signals to Qt ones. But as far as I can see it looks perfectly doable.
In playground there is code for dumping a .gir module and for generating the QMetaObjects. There are three classes; Smoke::MetaObjectBuilder for generating the QMetaObjects from the G-I repository, Smoke::GObjectProxy for invoking methods on the GObject classes via qt_metacall(), and a Smoke::GObectNamespace class for each G-I namespace with the constructor methods as slots and all the enums and flags for a namespace.
A dump of the Clutter QObjectNamespace instance looks like this:
Smoke::MetaObjectBuilder::createNamespace("Clutter");
Smoke::GObjectNamespace * gobjectNamespace = Smoke::MetaObjectBuilder::findNamespace("Clutter");
const QMetaObject* metaObject = gobjectNamespace->metaObject();
for(int i = metaObject->methodOffset(); i < metaObject->methodCount(); ++i) {
printf("%s\n", metaObject->method(i).signature());
}
// Gives this output:
Actor*Actor(Clutter::Vertex*,Clutter::ActorBox*)
Stage*Stage()
Stage*Stage()
Shader*Shader()
Timeline*Timeline(uint,uint)
Timeline*Timeline(uint)
Alpha*Alpha()
Alpha*Alpha(Clutter::Timeline*,Clutter::AlphaFunc*,void*,GLib::DestroyNotify*)
Group*Group()
BehaviourBspline*BehaviourBspline(Clutter::Alpha*,Clutter::Knot*,uint)
BehaviourDepth*BehaviourDepth(Clutter::Alpha*,int,int)
...
Or dumping the enums and flags for the namespace gives this output:
for(int i = metaObject->enumeratorOffset(); i < metaObject->enumeratorCount(); ++i) {
QMetaEnum enumerator = metaObject->enumerator(i);
printf("%s::%s\n", enumerator.scope(), enumerator.name());
for (int j = 0; j < enumerator.keyCount(); ++j) {
if (enumerator.isFlag()) {
printf(" %s = 0x%4.4x\n", enumerator.key(j), enumerator.value(j));
} else {
printf(" %s = %d\n", enumerator.key(j), enumerator.value(j));
}
}
}
// Gives this output:
Clutter::Gravity
None = 0
North = 1
NorthEast = 2
East = 3
SouthEast = 4
South = 5
SouthWest = 6
West = 7
NorthWest = 8
Center = 9
Clutter::RotateAxis
XAxis = 0
YAxis = 1
ZAxis = 2
Clutter::RotateDirection
Cw = 0
Ccw = 1
Clutter::RequestMode
HeightForWidth = 0
WidthForHeight = 1
Clutter::ModifierType
ShiftMask = 0x0001
LockMask = 0x0002
ControlMask = 0x0004
Mod1Mask = 0x0008
Mod2Mask = 0x0010
Mod3Mask = 0x0020
Mod4Mask = 0x0040
Mod5Mask = 0x0080
Button1Mask = 0x0100
Button2Mask = 0x0200
Button3Mask = 0x0400
Button4Mask = 0x0800
Button5Mask = 0x1000
...
The other QMetaObjects have slots, signals and properties for each GObject class with the names converted to camel case and Qt types replacing the GTK ones. It looks pretty 'Qt-like' to me. I had originally been thinking of making the binding entirely dynamic, but I now think it would be nice to optionally generate a C++ class heirachy as that wouldn't be too hard. That's all for now - watch this space for more news..