Skip to content

Commit

Permalink
hydrate objects constructed from GtkBuilder
Browse files Browse the repository at this point in the history
This runs JS constructors on objects that were not constructed from JavaScript. This is effectively objects constructed from GtkBuilder.

This is done by tracking all objects currently being constructed in a variable named `ConstructContext`. If an object's `TypeInfo`'s `instance_init` method (see https://docs.gtk.org/gobject/struct.TypeInfo.html) while it's gType is not the currently being constructed type (i.e. the last element of `ConstructContext`), it is assumed that the object is being constructed from GtkBuilder and the object's constructor is called, but instead of creating a new `GObject`, the constructed object's `gi:ref` (pointer) is passed instead, and the javascript "construction" continues.
  • Loading branch information
vixalien committed Dec 26, 2023
1 parent eda7f15 commit c80bcc1
Showing 1 changed file with 29 additions and 6 deletions.
35 changes: 29 additions & 6 deletions src/types/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,22 @@ function defineClassStructMethods(target, info) {
}
}

/** @type number | null */
export let _HydratingObject = null;
/** @type bigint | null */
let HydratingObject = null;

/**
* @param {bigint | null} object
*/
export function _setHydratingObject(object) {
HydratingObject = object;
}

/**
* An array of GTypes being currently constructed. This is to catch JS objects
* whose instance_init is called.
* @type bigint[]
*/
export const ConstructContext = [];

export function createObject(info, gType) {
const ParentClass = getParentClass(info) ?? Object;
Expand All @@ -109,22 +123,31 @@ export function createObject(info, gType) {
super(props);

if (gType == GType.OBJECT) {
if (_HydratingObject === null) {
const gType = Reflect.getOwnMetadata("gi:gtype", this.constructor);
const klass = this.constructor;

if (HydratingObject === null) {
const gType = Reflect.getOwnMetadata("gi:gtype", klass);

if (!gType) {
throw new Error("Tried to construct an object without a GType");
}

ConstructContext.push(gType);

Reflect.defineMetadata("gi:ref", g.object.new(gType, null), this);
Object.entries(props).forEach(([key, value]) => {
this[key] = value;
});

ConstructContext.pop();
} else {
Reflect.defineMetadata("gi:ref", _HydratingObject, this);
Reflect.defineMetadata("gi:ref", HydratingObject, this);

_HydratingObject = null;
HydratingObject = null;
}

const init_fn = Reflect.getMetadata("gi:instance_init", klass);
if (init_fn) init_fn.call(this);
}
}
};
Expand Down

0 comments on commit c80bcc1

Please sign in to comment.