Support class fields and class references in GObject subclasses
Depends on !701 (merged)
Example
class MyObject {
// Fields now work
specialField = 5;
doSomething() {
console.log(this.specialField);
}
static new_special() {
// Class self-references now work
return new MyObject({ ... });
}
};
GObject.registerClass(MyObject);
Background
This MR allows classes passed to GObject.registerClass to reference themselves and use class fields.
Instead of copying descriptors to a new, native class in registerClass, we can instead "wrap" the existing class constructor in the relevant GObject mechanics.
Because constructors chain and can return arbitrary objects, we rely on the GObject.Object constructor to return a native ObjectInstance which the child class can extend.
The native ObjectPrototype is stored in a private symbol on the JavaScript prototype and is used to resolve internally.
class MyObject extends GObject.Object {
constructor(...params) {
log("1");
super(...params);
log("5");
}
_init(...params) {
log("2");
super._init(...params);
log("4");
}
_instance_init(...params) {
log("3");
}
}
GObject.registerType(MyObject);
const myobj = new MyObject();
Lifecycle Hooks
Historically classes passed to GObject.registerClass
have relied on the ability to override or replace the existing constructor, this creates issues with newer JS class features like fields because they are installed after parent constructors. In the below example myfield
is initialized after the super()
call so any GObject mechanics triggered in _init
are overridden.
class MyObject extends GObject.Object {
myfield;
constructor(...params) {
log("1");
super(...params);
log("5");
}
_init(...params) {
log("2");
super._init(...params);
log("4");
}
_instance_init(...params) {
log("3");
}
}
GObject.registerClass(MyObject);
const myobj = new MyObject();
-
constructor
is called - super() triggers the parent constructor which calls
_init
(_init must chain still!) -
super._init
triggers_instance_init
-
_init
continues -
constructor
continues with a fully initialized object (fields applied)
Implementation Details
Before GObject.registerClass(TestObject)
class TestObject extends GObject.Object {
}
After GObject.registerClass(TestObject)
class TestObject extends GObject.Object {
static get $gtype() { return {Native GType Object} }
}
TestObject.prototype[Gi.gobject_prototype_symbol] = {Native Prototype Object}
Fixes #331 (closed)