From 8a80c5ed9ac2122c5c68f5ff99958a8a73ccdbca Mon Sep 17 00:00:00 2001 From: Angelo Verlain Date: Sun, 10 Dec 2023 22:15:33 +0200 Subject: [PATCH] support overrides also move gobject.object overrides to new file allowing to construct objects by extending --- src/bindings/girepository.js | 1 + src/gi.js | 3 ++ src/overrides/GObject.ts | 68 +++++++++++++++++++++++++++++++ src/overrides/mod.ts | 22 ++++++++++ src/types/object.js | 79 ++++++++++-------------------------- 5 files changed, 116 insertions(+), 57 deletions(-) create mode 100644 src/overrides/GObject.ts create mode 100644 src/overrides/mod.ts diff --git a/src/bindings/girepository.js b/src/bindings/girepository.js index c403002..3306631 100644 --- a/src/bindings/girepository.js +++ b/src/bindings/girepository.js @@ -24,6 +24,7 @@ const { g } = openLib(libName("girepository-1.0", 1), { }, base_info: { get_name: $string($pointer), + get_namespace: $string($pointer), is_deprecated: $bool($pointer), get_type: $i32($pointer), unref: $void($pointer), diff --git a/src/gi.js b/src/gi.js index 6bb1410..070a1a0 100644 --- a/src/gi.js +++ b/src/gi.js @@ -1,5 +1,6 @@ import g from "./bindings/mod.js"; import handleInfo from "./handleInfo.js"; +import { loadOverride } from "./overrides/mod.ts"; /** * @param {string} namespace @@ -25,5 +26,7 @@ export function require(namespace, version) { g.base_info.unref(info); } + loadOverride(namespace, repo); + return repo; } diff --git a/src/overrides/GObject.ts b/src/overrides/GObject.ts new file mode 100644 index 0000000..4b1c637 --- /dev/null +++ b/src/overrides/GObject.ts @@ -0,0 +1,68 @@ +// deno-lint-ignore-file no-explicit-any +import { GConnectFlags } from "../bindings/enums.js"; +import g from "../bindings/mod.js"; +import { createCallback } from "../types/callback.js"; + +type Handler = (...args: unknown[]) => unknown; + +function addObjectMethods(object: any) { + object.prototype.connect = function ( + action: string, + callback: Handler, + ) { + const signalInfo = Reflect.getMetadata( + "gi:signals", + this.constructor, + action.split("::")[0], + ); + + const cb = createCallback(signalInfo, callback, this); + const handler = g.signal.connect_data( + Reflect.getOwnMetadata("gi:ref", this), + action, + cb.pointer, + null, + null, + GConnectFlags.SWAPPED, + ); + + return handler; + }; + + object.prototype.on = function ( + action: string, + callback: Handler, + ) { + return this.connect(action, callback); + }; + + object.prototype.once = function ( + action: string, + callback: Handler, + ) { + const handler = this.connect(action, (...args: unknown[]) => { + callback(...args); + this.off(handler); + }); + + return handler; + }; + + object.prototype.off = function (handler: Handler) { + g.signal.handler_disconnect( + Reflect.getOwnMetadata("gi:ref", this), + handler as any, + ); + }; + + object.prototype.emit = function (action: string) { + g.signal.emit_by_name( + Reflect.getOwnMetadata("gi:ref", this), + action, + ); + }; +} + +export function _init(GObject: any) { + addObjectMethods(GObject.Object); +} diff --git a/src/overrides/mod.ts b/src/overrides/mod.ts new file mode 100644 index 0000000..23f857f --- /dev/null +++ b/src/overrides/mod.ts @@ -0,0 +1,22 @@ +import * as GObject from "./GObject.ts"; + +export interface GIOverride { + name: string; + version: string; + // deno-lint-ignore no-explicit-any + module: any; +} + +export const overrides: GIOverride[] = [ + { name: "GObject", version: "2.0", module: GObject }, +]; + +export function loadOverride(namespace: string, repo: unknown) { + const override = overrides.find((override) => { + return override.name === namespace; + }); + + if (override) { + override.module._init(repo); + } +} diff --git a/src/types/object.js b/src/types/object.js index ba29403..ad600ec 100644 --- a/src/types/object.js +++ b/src/types/object.js @@ -1,23 +1,19 @@ import g from "../bindings/mod.js"; import { getName } from "../utils/string.ts"; -import { handleCallable } from "./callable.js"; +import { handleCallable, handleMethod } from "./callable.js"; import { objectByGType } from "../utils/gobject.js"; -import { GConnectFlags } from "../bindings/enums.js"; -import { createCallback } from "./callback.js"; import { handleSignal } from "./signal.js"; import { handleProp } from "./prop.js"; -function extendObject(target, info) { +function getParentClass(info) { const parent = g.object_info.get_parent(info); if (parent) { const gType = g.registered_type_info.get_g_type(parent); const ParentClass = objectByGType(gType); - Object.setPrototypeOf(target.prototype, ParentClass.prototype); - //Object.assign(target.__signals__, ParentClass.__signals__); - g.base_info.unref(parent); + return ParentClass; } } @@ -86,60 +82,30 @@ function defineProps(target, info) { } } -export function createObject(info, gType) { - const ObjectClass = class { - constructor(props = {}) { - Reflect.defineMetadata("gi:ref", g.object.new(gType, null), this); - Object.entries(props).forEach(([key, value]) => { - this[key] = value; - }); - } +function defineStructMethods(target, structInfo) { + const nMethods = g.struct_info.get_n_methods(structInfo); - connect(action, callback) { - const signalInfo = Reflect.getMetadata( - "gi:signals", - ObjectClass, - action.split("::")[0], - ); - - const cb = createCallback(signalInfo, callback, this); - const handler = g.signal.connect_data( - Reflect.getOwnMetadata("gi:ref", this), - action, - cb.pointer, - null, - null, - GConnectFlags.SWAPPED, - ); - - return handler; - } - - on(action, callback) { - return this.connect(action, callback); + for (let i = 0; i < nMethods; i++) { + const methodInfo = g.struct_info.get_method(structInfo, i); + if (!Object.hasOwn(target.prototype, getName(methodInfo))) { + handleMethod(target, methodInfo); } + } +} - once(action, callback) { - const handler = this.connect(action, (...args) => { - callback(...args); - this.off(handler); - }); +export function createObject(info, gType) { + const ParentClass = getParentClass(info) ?? Object; - return handler; - } + const ObjectClass = class extends ParentClass { + constructor(props = {}, init = true) { + super(props, false); - off(handler) { - g.signal.handler_disconnect( - Reflect.getOwnMetadata("gi:ref", this), - handler, - ); - } - - emit(action) { - g.signal.emit_by_name( - Reflect.getOwnMetadata("gi:ref", this), - action, - ); + if (init) { + Reflect.defineMetadata("gi:ref", g.object.new(gType, null), this); + Object.entries(props).forEach(([key, value]) => { + this[key] = value; + }); + } } }; @@ -153,7 +119,6 @@ export function createObject(info, gType) { defineVFuncs(ObjectClass, info); defineSignals(ObjectClass, info); defineProps(ObjectClass, info); - extendObject(ObjectClass, info); inheritInterfaces(ObjectClass, info); return ObjectClass;