@gtkx/runtime 0.0.1 → 1.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +171 -3
  3. package/dist/arg.d.ts +12 -0
  4. package/dist/arg.d.ts.map +1 -0
  5. package/dist/arg.js +5 -0
  6. package/dist/arg.js.map +1 -0
  7. package/dist/bind.d.ts +4 -0
  8. package/dist/bind.d.ts.map +1 -0
  9. package/dist/bind.js +17 -0
  10. package/dist/bind.js.map +1 -0
  11. package/dist/callback.d.ts +13 -0
  12. package/dist/callback.d.ts.map +1 -0
  13. package/dist/callback.js +68 -0
  14. package/dist/callback.js.map +1 -0
  15. package/dist/descriptors.d.ts +155 -0
  16. package/dist/descriptors.d.ts.map +1 -0
  17. package/dist/descriptors.js +103 -0
  18. package/dist/descriptors.js.map +1 -0
  19. package/dist/error.d.ts +25 -0
  20. package/dist/error.d.ts.map +1 -0
  21. package/dist/error.js +29 -0
  22. package/dist/error.js.map +1 -0
  23. package/dist/fn.d.ts +10 -0
  24. package/dist/fn.d.ts.map +1 -0
  25. package/dist/fn.js +79 -0
  26. package/dist/fn.js.map +1 -0
  27. package/dist/index.d.ts +15 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +15 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/internal.d.ts +5 -0
  32. package/dist/internal.d.ts.map +1 -0
  33. package/dist/internal.js +5 -0
  34. package/dist/internal.js.map +1 -0
  35. package/dist/library.d.ts +7 -0
  36. package/dist/library.d.ts.map +1 -0
  37. package/dist/library.js +13 -0
  38. package/dist/library.js.map +1 -0
  39. package/dist/lifecycle.d.ts +41 -0
  40. package/dist/lifecycle.d.ts.map +1 -0
  41. package/dist/lifecycle.js +55 -0
  42. package/dist/lifecycle.js.map +1 -0
  43. package/dist/listeners.d.ts +36 -0
  44. package/dist/listeners.d.ts.map +1 -0
  45. package/dist/listeners.js +72 -0
  46. package/dist/listeners.js.map +1 -0
  47. package/dist/mixin.d.ts +19 -0
  48. package/dist/mixin.d.ts.map +1 -0
  49. package/dist/mixin.js +39 -0
  50. package/dist/mixin.js.map +1 -0
  51. package/dist/native-value.d.ts +12 -0
  52. package/dist/native-value.d.ts.map +1 -0
  53. package/dist/native-value.js +72 -0
  54. package/dist/native-value.js.map +1 -0
  55. package/dist/object.d.ts +31 -0
  56. package/dist/object.d.ts.map +1 -0
  57. package/dist/object.js +63 -0
  58. package/dist/object.js.map +1 -0
  59. package/dist/promisify.d.ts +13 -0
  60. package/dist/promisify.d.ts.map +1 -0
  61. package/dist/promisify.js +36 -0
  62. package/dist/promisify.js.map +1 -0
  63. package/dist/register-class.d.ts +17 -0
  64. package/dist/register-class.d.ts.map +1 -0
  65. package/dist/register-class.js +124 -0
  66. package/dist/register-class.js.map +1 -0
  67. package/dist/registry.d.ts +67 -0
  68. package/dist/registry.d.ts.map +1 -0
  69. package/dist/registry.js +167 -0
  70. package/dist/registry.js.map +1 -0
  71. package/dist/signal.d.ts +34 -0
  72. package/dist/signal.d.ts.map +1 -0
  73. package/dist/signal.js +88 -0
  74. package/dist/signal.js.map +1 -0
  75. package/dist/t.d.ts +50 -0
  76. package/dist/t.d.ts.map +1 -0
  77. package/dist/t.js +48 -0
  78. package/dist/t.js.map +1 -0
  79. package/dist/tuple.d.ts +6 -0
  80. package/dist/tuple.d.ts.map +1 -0
  81. package/dist/tuple.js +23 -0
  82. package/dist/tuple.js.map +1 -0
  83. package/dist/type.d.ts +81 -0
  84. package/dist/type.d.ts.map +1 -0
  85. package/dist/type.js +174 -0
  86. package/dist/type.js.map +1 -0
  87. package/dist/value.d.ts +20 -0
  88. package/dist/value.d.ts.map +1 -0
  89. package/dist/value.js +227 -0
  90. package/dist/value.js.map +1 -0
  91. package/package.json +56 -13
  92. package/src/arg.ts +13 -0
  93. package/src/bind.ts +22 -0
  94. package/src/callback.ts +87 -0
  95. package/src/descriptors.ts +208 -0
  96. package/src/error.ts +49 -0
  97. package/src/fn.ts +108 -0
  98. package/src/index.ts +57 -0
  99. package/src/internal.ts +12 -0
  100. package/src/library.ts +15 -0
  101. package/src/lifecycle.ts +73 -0
  102. package/src/listeners.ts +84 -0
  103. package/src/mixin.ts +48 -0
  104. package/src/native-value.ts +78 -0
  105. package/src/object.ts +83 -0
  106. package/src/promisify.ts +40 -0
  107. package/src/register-class.ts +178 -0
  108. package/src/registry.ts +221 -0
  109. package/src/signal.ts +152 -0
  110. package/src/t.ts +88 -0
  111. package/src/tuple.ts +25 -0
  112. package/src/type.ts +200 -0
  113. package/src/value.ts +307 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promisify.js","sourceRoot":"","sources":["../src/promisify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,mBAAmB,GAAG,CAAC,KAAc,EAAE,aAAgC,EAAQ,EAAE;IACnF,IAAI,aAAa,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC;QAAE,OAAO;IACrE,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC;QAAE,OAAO;IACrE,KAAK,CAAC,KAAK,GAAG,aAAa,CAAC;AAChC,CAAC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CACrB,OAAqC,EACrC,MAAwB,EACxB,WAAsC,EACtC,GAAG,OAAkB,EACX,EAAE,CACZ,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC/B,IAAI,aAAgC,CAAC;IACrC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QACxC,aAAa,GAAG,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QAC/D,KAAK,CAAC,iBAAiB,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,CAAC,GAAG,OAAO,EAAE,YAAY,CAAC,WAAW,CAAC,EAAE,CAAC,OAAsB,EAAE,WAAmB,EAAE,EAAE;QAC3F,IAAI,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,WAAgB,CAAC,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,mBAAmB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;YAC1C,MAAM,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC","sourcesContent":["import { tryGetHandle } from \"./registry.js\";\n\nconst attachCreationStack = (error: unknown, creationStack: Error | undefined): void => {\n if (creationStack === undefined || !(error instanceof Error)) return;\n if (error.cause !== undefined || !Object.isExtensible(error)) return;\n error.cause = creationStack;\n};\n\n/**\n * Wraps a GIO-style asynchronous function that takes a completion callback into a\n * promise, invoking the finish function to extract the result. Outside production,\n * the call site's stack is captured and attached as the rejection error's cause.\n *\n * @param asyncFn The async function, called with the leading arguments, the cancellable, and a completion callback.\n * @param finish Extracts the result from the async result passed to the completion callback.\n * @param cancellable A cancellable object, or null/undefined for none.\n * @param leading Arguments passed to `asyncFn` before the cancellable and callback.\n * @returns A promise resolving to the finished result, or rejecting if `finish` throws.\n */\nexport const promisify = <R extends object, T>(\n asyncFn: (...args: unknown[]) => void,\n finish: (result: R) => T,\n cancellable: object | null | undefined,\n ...leading: unknown[]\n): Promise<T> =>\n new Promise<T>((resolve, reject) => {\n let creationStack: Error | undefined;\n if (process.env.NODE_ENV !== \"production\") {\n creationStack = new Error(\"gtkx async operation started here\");\n Error.captureStackTrace(creationStack, promisify);\n }\n asyncFn(...leading, tryGetHandle(cancellable), (_source: object | null, asyncResult: object) => {\n try {\n resolve(finish(asyncResult as R));\n } catch (error) {\n attachCreationStack(error, creationStack);\n reject(error);\n }\n });\n });\n"]}
@@ -0,0 +1,17 @@
1
+ import { type AnyClass } from "@gtkx/utils";
2
+ type RegisterClassOptions = {
3
+ typeName?: string;
4
+ };
5
+ /**
6
+ * Registers a subclass of a wrapper class as a new GType, wiring up any class and
7
+ * inherited-interface virtual functions it overrides. Throws if the class does not
8
+ * extend a registered wrapper class, has no derivable type name, or overrides an
9
+ * unsupported construct-time vtable slot.
10
+ *
11
+ * @param klass The subclass to register.
12
+ * @param options Registration options, such as an explicit type name.
13
+ * @returns The same class, now registered.
14
+ */
15
+ export declare function registerClass<T extends AnyClass>(klass: T, options?: RegisterClassOptions): T;
16
+ export {};
17
+ //# sourceMappingURL=register-class.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-class.d.ts","sourceRoot":"","sources":["../src/register-class.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,QAAQ,EAAkC,MAAM,aAAa,CAAC;AAW5E,KAAK,oBAAoB,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAOlD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,GAAE,oBAAyB,GAAG,CAAC,CAqBjG"}
@@ -0,0 +1,124 @@
1
+ import { registerClass as nativeRegisterClass, } from "@gtkx/native";
2
+ import { getParentClass, walkClassChain } from "@gtkx/utils";
3
+ import { wrapCallback } from "./callback.js";
4
+ import { getClassType, getInterfaceVfuncRegistry, getVfuncRegistry, registerClassType, } from "./registry.js";
5
+ import { TYPE_INVALID, typeInterfaces } from "./type.js";
6
+ /**
7
+ * Registers a subclass of a wrapper class as a new GType, wiring up any class and
8
+ * inherited-interface virtual functions it overrides. Throws if the class does not
9
+ * extend a registered wrapper class, has no derivable type name, or overrides an
10
+ * unsupported construct-time vtable slot.
11
+ *
12
+ * @param klass The subclass to register.
13
+ * @param options Registration options, such as an explicit type name.
14
+ * @returns The same class, now registered.
15
+ */
16
+ export function registerClass(klass, options = {}) {
17
+ const parentType = resolveParentType(klass);
18
+ if (parentType === TYPE_INVALID) {
19
+ throw new TypeError(`registerClass: ${klass.name} must extend a registered wrapper class`);
20
+ }
21
+ const name = options.typeName ?? klass.name;
22
+ if (!name) {
23
+ throw new Error("registerClass: cannot derive a GType name (anonymous class with no typeName option)");
24
+ }
25
+ const classVfuncs = discoverClassVfuncs(klass);
26
+ const claimedMethodNames = new Set(classVfuncs.map((vfunc) => vfunc.methodName));
27
+ const interfaceBindings = discoverInheritedInterfaceVfuncs(klass, parentType, claimedMethodNames);
28
+ const nativeOptions = toNativeOptions(classVfuncs, interfaceBindings);
29
+ const newType = nativeRegisterClass(name, parentType, nativeOptions);
30
+ registerClassType(klass, newType);
31
+ return klass;
32
+ }
33
+ function resolveParentType(klass) {
34
+ return (walkClassChain(getParentClass(klass), (cls) => {
35
+ const gtype = getClassType(cls);
36
+ return gtype !== TYPE_INVALID ? gtype : undefined;
37
+ }) ?? TYPE_INVALID);
38
+ }
39
+ function ownInstanceMethodNames(klass) {
40
+ const proto = klass.prototype;
41
+ if (!proto)
42
+ return [];
43
+ return Object.getOwnPropertyNames(proto).filter((name) => {
44
+ if (name === "constructor")
45
+ return false;
46
+ return typeof proto[name] === "function";
47
+ });
48
+ }
49
+ function collectDiscoveredVfuncs(klass, resolveDescriptor, skip) {
50
+ const proto = klass.prototype;
51
+ const result = [];
52
+ for (const methodName of ownInstanceMethodNames(klass)) {
53
+ if (skip?.has(methodName))
54
+ continue;
55
+ const descriptor = resolveDescriptor(methodName);
56
+ if (!descriptor)
57
+ continue;
58
+ const fn = proto[methodName];
59
+ if (!fn)
60
+ continue;
61
+ result.push({
62
+ ...descriptor,
63
+ methodName,
64
+ fn: wrapVfunc(fn, descriptor.argDescriptors, descriptor.returnDescriptor),
65
+ });
66
+ }
67
+ return result;
68
+ }
69
+ const UNSUPPORTED_CONSTRUCT_VFUNCS = new Set(["constructed", "setProperty", "getProperty"]);
70
+ function discoverClassVfuncs(klass) {
71
+ return collectDiscoveredVfuncs(klass, (methodName) => {
72
+ const descriptor = findClassVfuncDescriptor(klass, methodName);
73
+ if (descriptor && UNSUPPORTED_CONSTRUCT_VFUNCS.has(methodName)) {
74
+ throw new Error(`registerClass: overriding the GObject construct-time vtable slot '${methodName}' is not supported; run construct-time initialization in the subclass constructor, after super(...), instead`);
75
+ }
76
+ return descriptor ?? undefined;
77
+ });
78
+ }
79
+ function wrapVfunc(fn, argDescriptors, returnDescriptor) {
80
+ return wrapCallback(fn, { argDescriptors, returnDescriptor }, "this");
81
+ }
82
+ function discoverInheritedInterfaceVfuncs(klass, parentGtype, claimedMethodNames) {
83
+ const bindings = [];
84
+ for (const interfaceGtype of typeInterfaces(parentGtype)) {
85
+ const vfuncs = discoverInterfaceVfuncs(klass, interfaceGtype, claimedMethodNames);
86
+ if (vfuncs.length > 0) {
87
+ bindings.push({ gtype: interfaceGtype, vfuncs });
88
+ }
89
+ }
90
+ return bindings;
91
+ }
92
+ function discoverInterfaceVfuncs(klass, interfaceGtype, claimedMethodNames) {
93
+ const vfuncRegistry = getInterfaceVfuncRegistry(interfaceGtype);
94
+ if (!vfuncRegistry)
95
+ return [];
96
+ return collectDiscoveredVfuncs(klass, (methodName) => {
97
+ const entry = vfuncRegistry[methodName];
98
+ return entry?.kind === "interface" ? entry : undefined;
99
+ }, claimedMethodNames);
100
+ }
101
+ function findClassVfuncDescriptor(klass, methodName) {
102
+ return (walkClassChain(getParentClass(klass), (cls) => {
103
+ const entry = getVfuncRegistry(cls)?.[methodName];
104
+ return entry?.kind === "class" ? entry : undefined;
105
+ }) ?? null);
106
+ }
107
+ function toNativeOptions(classVfuncs, interfaceBindings) {
108
+ const hasInterfaces = interfaceBindings.length > 0;
109
+ const hasClassVfuncs = classVfuncs.length > 0;
110
+ if (!hasClassVfuncs && !hasInterfaces) {
111
+ return undefined;
112
+ }
113
+ const options = {};
114
+ if (hasClassVfuncs)
115
+ options.vfuncs = [...classVfuncs];
116
+ if (hasInterfaces) {
117
+ options.interfaces = interfaceBindings.map((binding) => ({
118
+ type: binding.gtype,
119
+ vfuncs: [...binding.vfuncs],
120
+ }));
121
+ }
122
+ return options;
123
+ }
124
+ //# sourceMappingURL=register-class.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-class.js","sourceRoot":"","sources":["../src/register-class.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type RegisterClassOptions as NativeRegisterClassOptions,\n type RegisterClassVfunc as NativeRegisterClassVfunc,\n registerClass as nativeRegisterClass,\n} from \"@gtkx/native\";\nimport { type AnyClass, getParentClass, walkClassChain } from \"@gtkx/utils\";\nimport { wrapCallback } from \"./callback.js\";\nimport {\n getClassType,\n getInterfaceVfuncRegistry,\n getVfuncRegistry,\n registerClassType,\n type VfuncDescriptor,\n} from \"./registry.js\";\nimport { TYPE_INVALID, typeInterfaces } from \"./type.js\";\n\ntype RegisterClassOptions = { typeName?: string };\ntype VfuncFn = NativeRegisterClassVfunc[\"fn\"];\ntype DiscoveredVfunc<K extends \"class\" | \"interface\"> = VfuncDescriptor<K> & { methodName: string; fn: VfuncFn };\ntype DiscoveredClassVfunc = DiscoveredVfunc<\"class\">;\ntype DiscoveredInterfaceVfunc = DiscoveredVfunc<\"interface\">;\ntype InterfaceVfuncBinding = { gtype: bigint; vfuncs: DiscoveredInterfaceVfunc[] };\n\n/**\n * Registers a subclass of a wrapper class as a new GType, wiring up any class and\n * inherited-interface virtual functions it overrides. Throws if the class does not\n * extend a registered wrapper class, has no derivable type name, or overrides an\n * unsupported construct-time vtable slot.\n *\n * @param klass The subclass to register.\n * @param options Registration options, such as an explicit type name.\n * @returns The same class, now registered.\n */\nexport function registerClass<T extends AnyClass>(klass: T, options: RegisterClassOptions = {}): T {\n const parentType = resolveParentType(klass);\n if (parentType === TYPE_INVALID) {\n throw new TypeError(`registerClass: ${klass.name} must extend a registered wrapper class`);\n }\n\n const name = options.typeName ?? klass.name;\n\n if (!name) {\n throw new Error(\"registerClass: cannot derive a GType name (anonymous class with no typeName option)\");\n }\n\n const classVfuncs = discoverClassVfuncs(klass);\n const claimedMethodNames = new Set(classVfuncs.map((vfunc) => vfunc.methodName));\n const interfaceBindings = discoverInheritedInterfaceVfuncs(klass, parentType, claimedMethodNames);\n\n const nativeOptions = toNativeOptions(classVfuncs, interfaceBindings);\n const newType: bigint = nativeRegisterClass(name, parentType, nativeOptions);\n registerClassType(klass, newType);\n\n return klass;\n}\n\nfunction resolveParentType(klass: AnyClass): bigint {\n return (\n walkClassChain(getParentClass(klass), (cls) => {\n const gtype = getClassType(cls);\n return gtype !== TYPE_INVALID ? gtype : undefined;\n }) ?? TYPE_INVALID\n );\n}\n\nfunction ownInstanceMethodNames(klass: AnyClass): string[] {\n const proto = (klass as { prototype?: object }).prototype;\n if (!proto) return [];\n return Object.getOwnPropertyNames(proto).filter((name) => {\n if (name === \"constructor\") return false;\n return typeof (proto as Record<string, unknown>)[name] === \"function\";\n });\n}\n\nfunction collectDiscoveredVfuncs<K extends \"class\" | \"interface\">(\n klass: AnyClass,\n resolveDescriptor: (methodName: string) => VfuncDescriptor<K> | undefined,\n skip?: Set<string>,\n): DiscoveredVfunc<K>[] {\n const proto = (klass as { prototype: Record<string, VfuncFn> }).prototype;\n const result: DiscoveredVfunc<K>[] = [];\n for (const methodName of ownInstanceMethodNames(klass)) {\n if (skip?.has(methodName)) continue;\n const descriptor = resolveDescriptor(methodName);\n if (!descriptor) continue;\n const fn = proto[methodName];\n if (!fn) continue;\n result.push({\n ...descriptor,\n methodName,\n fn: wrapVfunc(fn, descriptor.argDescriptors, descriptor.returnDescriptor),\n });\n }\n return result;\n}\n\nconst UNSUPPORTED_CONSTRUCT_VFUNCS: Set<string> = new Set([\"constructed\", \"setProperty\", \"getProperty\"]);\n\nfunction discoverClassVfuncs(klass: AnyClass): DiscoveredClassVfunc[] {\n return collectDiscoveredVfuncs(klass, (methodName) => {\n const descriptor = findClassVfuncDescriptor(klass, methodName);\n if (descriptor && UNSUPPORTED_CONSTRUCT_VFUNCS.has(methodName)) {\n throw new Error(\n `registerClass: overriding the GObject construct-time vtable slot '${methodName}' is not supported; run construct-time initialization in the subclass constructor, after super(...), instead`,\n );\n }\n return descriptor ?? undefined;\n });\n}\n\nfunction wrapVfunc(\n fn: VfuncFn,\n argDescriptors: NativeRegisterClassVfunc[\"argDescriptors\"],\n returnDescriptor: NativeRegisterClassVfunc[\"returnDescriptor\"],\n): VfuncFn {\n return wrapCallback(fn as (...args: unknown[]) => unknown, { argDescriptors, returnDescriptor }, \"this\");\n}\n\nfunction discoverInheritedInterfaceVfuncs(\n klass: AnyClass,\n parentGtype: bigint,\n claimedMethodNames: Set<string>,\n): InterfaceVfuncBinding[] {\n const bindings: InterfaceVfuncBinding[] = [];\n for (const interfaceGtype of typeInterfaces(parentGtype)) {\n const vfuncs = discoverInterfaceVfuncs(klass, interfaceGtype, claimedMethodNames);\n if (vfuncs.length > 0) {\n bindings.push({ gtype: interfaceGtype, vfuncs });\n }\n }\n return bindings;\n}\n\nfunction discoverInterfaceVfuncs(\n klass: AnyClass,\n interfaceGtype: bigint,\n claimedMethodNames: Set<string>,\n): DiscoveredInterfaceVfunc[] {\n const vfuncRegistry = getInterfaceVfuncRegistry(interfaceGtype);\n if (!vfuncRegistry) return [];\n return collectDiscoveredVfuncs(\n klass,\n (methodName) => {\n const entry = vfuncRegistry[methodName];\n return entry?.kind === \"interface\" ? entry : undefined;\n },\n claimedMethodNames,\n );\n}\n\nfunction findClassVfuncDescriptor(klass: AnyClass, methodName: string): VfuncDescriptor<\"class\"> | null {\n return (\n walkClassChain(getParentClass(klass), (cls) => {\n const entry = getVfuncRegistry(cls)?.[methodName];\n return entry?.kind === \"class\" ? entry : undefined;\n }) ?? null\n );\n}\n\nfunction toNativeOptions(\n classVfuncs: DiscoveredClassVfunc[],\n interfaceBindings: InterfaceVfuncBinding[],\n): NativeRegisterClassOptions | undefined {\n const hasInterfaces = interfaceBindings.length > 0;\n const hasClassVfuncs = classVfuncs.length > 0;\n if (!hasClassVfuncs && !hasInterfaces) {\n return undefined;\n }\n const options: NativeRegisterClassOptions = {};\n if (hasClassVfuncs) options.vfuncs = [...classVfuncs];\n if (hasInterfaces) {\n options.interfaces = interfaceBindings.map((binding) => ({\n type: binding.gtype,\n vfuncs: [...binding.vfuncs],\n }));\n }\n return options;\n}\n"]}
@@ -0,0 +1,67 @@
1
+ import { type ExternalObject, type Handle, type RegisterClassVfunc as NativeRegisterClassVfunc } from "@gtkx/native";
2
+ import type { AnyClass } from "@gtkx/utils";
3
+ import type { Mixin } from "./mixin.js";
4
+ import { type TypedClass } from "./type.js";
5
+ /**
6
+ * Static side of class `C` with its construct signature preserved but the member
7
+ * named `K` (default `"new"`) removed.
8
+ */
9
+ export type StaticBase<C, K extends PropertyKey = "new"> = Omit<C, K> & (C extends new (...args: infer A) => infer R ? new (...args: A) => R : never);
10
+ export type VfuncDescriptor<K extends "class" | "interface"> = {
11
+ kind: K;
12
+ className: string;
13
+ vfuncName: string;
14
+ byteOffset: number;
15
+ argDescriptors: NativeRegisterClassVfunc["argDescriptors"];
16
+ returnDescriptor: NativeRegisterClassVfunc["returnDescriptor"];
17
+ };
18
+ export type VfuncRegistry = Record<string, VfuncDescriptor<"class"> | VfuncDescriptor<"interface">>;
19
+ export declare function getClassType(cls: AnyClass): bigint;
20
+ /** Returns the GType tag of the given wrapper instance. */
21
+ export declare function getInstanceType(instance: object): bigint;
22
+ export declare function registerClassType(cls: AnyClass, type: bigint): void;
23
+ /**
24
+ * Registers a wrapper class as the JS representation of a GType, optionally
25
+ * installing a registry of virtual functions.
26
+ * @param cls Wrapper class to associate with the type.
27
+ * @param type GType the class wraps.
28
+ * @param vfuncs Virtual functions the class overrides.
29
+ */
30
+ export declare function registerWrapperClass(cls: AnyClass, type: bigint, vfuncs?: VfuncRegistry): void;
31
+ /**
32
+ * Registers a GInterface, associating its GType with a mixin used to compose the
33
+ * interface onto wrapper classes and an optional virtual function registry.
34
+ * @param cls Class carrying the interface's GType tag.
35
+ * @param type GType of the interface.
36
+ * @param mixin Mixin that applies the interface to a wrapper class.
37
+ * @param vfuncs Virtual functions the interface exposes.
38
+ */
39
+ export declare function registerInterface(cls: AnyClass, type: bigint, mixin: Mixin, vfuncs?: VfuncRegistry): void;
40
+ /**
41
+ * Wraps a native handle in a JS wrapper instance. With no class, resolves and
42
+ * reuses the wrapper for the handle's runtime GType (composing interface mixins);
43
+ * with an explicit class, creates a bare instance backed by the handle. Returns
44
+ * null for a null or undefined handle.
45
+ * @param handle Native handle to wrap.
46
+ * @param cls Wrapper class to instantiate, or omitted to resolve it from the runtime type.
47
+ */
48
+ export declare function wrapHandle(handle: null | undefined, cls?: AnyClass): null;
49
+ export declare function wrapHandle<T extends object>(handle: ExternalObject<Handle>, cls: AnyClass<T>): T;
50
+ export declare function wrapHandle<T extends object>(handle: ExternalObject<Handle> | null | undefined, cls: AnyClass<T>): T | null;
51
+ export declare function wrapHandle<T extends object = TypedClass>(handle: ExternalObject<Handle>, cls?: AnyClass): T;
52
+ export declare function wrapHandle<T extends object = TypedClass>(handle: ExternalObject<Handle> | null | undefined, cls?: AnyClass): T | null;
53
+ /**
54
+ * Returns the wrapper class registered for a GType, walking up to ancestor types,
55
+ * and throws if none is registered.
56
+ */
57
+ export declare function getWrapperClass(type: bigint): AnyClass;
58
+ export declare function resolveWrapperClass(type: bigint): AnyClass | null;
59
+ /** Returns the native handle bound to a wrapper instance, throwing if none is set. */
60
+ export declare function getHandle(instance: object): ExternalObject<Handle>;
61
+ /** Returns the native handle bound to an instance, or undefined when there is none or the instance is null. */
62
+ export declare function tryGetHandle(instance: object | null | undefined): ExternalObject<Handle> | undefined;
63
+ /** Associates a native handle with a wrapper instance. */
64
+ export declare function setHandle(instance: object, handle: ExternalObject<Handle>): void;
65
+ export declare function getVfuncRegistry(cls: object): VfuncRegistry | undefined;
66
+ export declare function getInterfaceVfuncRegistry(type: bigint): VfuncRegistry | undefined;
67
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,167 @@
1
+ import { getType, getWrapper, setWrapper, } from "@gtkx/native";
2
+ import { TYPE_INVALID, typeInterfaces, typeIsA, typeName, typeParent } from "./type.js";
3
+ const classRegistry = new Map();
4
+ const interfaceMixinRegistry = new Map();
5
+ const composedClassRegistry = new Map();
6
+ const handleMap = new WeakMap();
7
+ const vfuncRegistry = new WeakMap();
8
+ const interfaceVfuncRegistry = new Map();
9
+ function setClassType(cls, type) {
10
+ cls.prototype.__type__ = type;
11
+ }
12
+ export function getClassType(cls) {
13
+ const proto = cls.prototype;
14
+ return Object.hasOwn(proto, "__type__") ? proto.__type__ : TYPE_INVALID;
15
+ }
16
+ /** Returns the GType tag of the given wrapper instance. */
17
+ export function getInstanceType(instance) {
18
+ return getClassType(instance.constructor);
19
+ }
20
+ export function registerClassType(cls, type) {
21
+ if (type !== TYPE_INVALID) {
22
+ classRegistry.set(type, cls);
23
+ setClassType(cls, type);
24
+ }
25
+ }
26
+ /**
27
+ * Registers a wrapper class as the JS representation of a GType, optionally
28
+ * installing a registry of virtual functions.
29
+ * @param cls Wrapper class to associate with the type.
30
+ * @param type GType the class wraps.
31
+ * @param vfuncs Virtual functions the class overrides.
32
+ */
33
+ export function registerWrapperClass(cls, type, vfuncs) {
34
+ registerClassType(cls, type);
35
+ if (vfuncs)
36
+ registerVfuncRegistry(cls, vfuncs);
37
+ }
38
+ /**
39
+ * Registers a GInterface, associating its GType with a mixin used to compose the
40
+ * interface onto wrapper classes and an optional virtual function registry.
41
+ * @param cls Class carrying the interface's GType tag.
42
+ * @param type GType of the interface.
43
+ * @param mixin Mixin that applies the interface to a wrapper class.
44
+ * @param vfuncs Virtual functions the interface exposes.
45
+ */
46
+ export function registerInterface(cls, type, mixin, vfuncs) {
47
+ if (type === TYPE_INVALID)
48
+ return;
49
+ setClassType(cls, type);
50
+ interfaceMixinRegistry.set(type, mixin);
51
+ if (vfuncs)
52
+ registerInterfaceVfuncRegistry(type, vfuncs);
53
+ }
54
+ export function wrapHandle(handle, cls) {
55
+ if (handle === null || handle === undefined)
56
+ return null;
57
+ if (cls === undefined) {
58
+ return getOrCreateWrapper(handle);
59
+ }
60
+ const instance = Object.create(cls.prototype);
61
+ setHandle(instance, handle);
62
+ return instance;
63
+ }
64
+ /**
65
+ * Returns the wrapper class registered for a GType, walking up to ancestor types,
66
+ * and throws if none is registered.
67
+ */
68
+ export function getWrapperClass(type) {
69
+ const cls = resolveWrapperClass(type);
70
+ if (!cls) {
71
+ throw new Error(`No registered wrapper class for type '${typeName(type) ?? String(type)}'`);
72
+ }
73
+ return cls;
74
+ }
75
+ export function resolveWrapperClass(type) {
76
+ let currentType = type;
77
+ while (currentType !== TYPE_INVALID) {
78
+ const cls = classRegistry.get(currentType);
79
+ if (cls)
80
+ return cls;
81
+ currentType = typeParent(currentType);
82
+ }
83
+ return null;
84
+ }
85
+ function createComposedClass(base, runtimeType) {
86
+ const baseType = getClassType(base);
87
+ const applied = new Set();
88
+ let cls = base;
89
+ for (const type of typeInterfaces(runtimeType)) {
90
+ if (applied.has(type) || typeIsA(baseType, type))
91
+ continue;
92
+ const mixin = interfaceMixinRegistry.get(type);
93
+ if (mixin === undefined)
94
+ continue;
95
+ applied.add(type);
96
+ cls = mixin(cls);
97
+ }
98
+ return applied.size === 0 ? base : cls;
99
+ }
100
+ function resolveComposedClass(runtimeType) {
101
+ const exact = classRegistry.get(runtimeType);
102
+ if (exact)
103
+ return exact;
104
+ const cached = composedClassRegistry.get(runtimeType);
105
+ if (cached)
106
+ return cached;
107
+ const base = resolveWrapperClass(runtimeType);
108
+ if (base === null)
109
+ return null;
110
+ const composed = createComposedClass(base, runtimeType);
111
+ if (composed === base)
112
+ return base;
113
+ setClassType(composed, runtimeType);
114
+ composedClassRegistry.set(runtimeType, composed);
115
+ return composed;
116
+ }
117
+ function getOrCreateWrapper(handle) {
118
+ const existing = getWrapper(handle);
119
+ if (existing)
120
+ return existing;
121
+ const runtimeType = getType(handle);
122
+ if (runtimeType === TYPE_INVALID) {
123
+ throw new Error("Cannot resolve runtime GLib type from handle");
124
+ }
125
+ const cls = resolveComposedClass(runtimeType);
126
+ if (!cls)
127
+ throw new Error(`Expected registered GLib type, got type ${String(runtimeType)}`);
128
+ const instance = Object.create(cls.prototype);
129
+ registerWrapper(handle, instance);
130
+ return instance;
131
+ }
132
+ /** Returns the native handle bound to a wrapper instance, throwing if none is set. */
133
+ export function getHandle(instance) {
134
+ const handle = handleMap.get(instance);
135
+ if (handle === undefined) {
136
+ const name = instance.constructor?.name ?? "object";
137
+ throw new Error(`No native handle associated with ${name}`);
138
+ }
139
+ return handle;
140
+ }
141
+ /** Returns the native handle bound to an instance, or undefined when there is none or the instance is null. */
142
+ export function tryGetHandle(instance) {
143
+ return instance == null ? undefined : handleMap.get(instance);
144
+ }
145
+ /** Associates a native handle with a wrapper instance. */
146
+ export function setHandle(instance, handle) {
147
+ handleMap.set(instance, handle);
148
+ }
149
+ function registerWrapper(handle, instance) {
150
+ setHandle(instance, handle);
151
+ setWrapper(handle, instance);
152
+ }
153
+ function registerVfuncRegistry(cls, registry) {
154
+ vfuncRegistry.set(cls, registry);
155
+ }
156
+ export function getVfuncRegistry(cls) {
157
+ return vfuncRegistry.get(cls);
158
+ }
159
+ function registerInterfaceVfuncRegistry(type, registry) {
160
+ if (type === TYPE_INVALID)
161
+ return;
162
+ interfaceVfuncRegistry.set(type, registry);
163
+ }
164
+ export function getInterfaceVfuncRegistry(type) {
165
+ return interfaceVfuncRegistry.get(type);
166
+ }
167
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ExternalObject,\n getType,\n getWrapper,\n type Handle,\n type RegisterClassVfunc as NativeRegisterClassVfunc,\n setWrapper,\n} from \"@gtkx/native\";\nimport type { AnyClass } from \"@gtkx/utils\";\nimport type { Mixin, MixinReceiver } from \"./mixin.js\";\nimport { TYPE_INVALID, type TypedClass, typeInterfaces, typeIsA, typeName, typeParent } from \"./type.js\";\n\n/**\n * Static side of class `C` with its construct signature preserved but the member\n * named `K` (default `\"new\"`) removed.\n */\nexport type StaticBase<C, K extends PropertyKey = \"new\"> = Omit<C, K> &\n (C extends new (...args: infer A) => infer R ? new (...args: A) => R : never);\n\nexport type VfuncDescriptor<K extends \"class\" | \"interface\"> = {\n kind: K;\n className: string;\n vfuncName: string;\n byteOffset: number;\n argDescriptors: NativeRegisterClassVfunc[\"argDescriptors\"];\n returnDescriptor: NativeRegisterClassVfunc[\"returnDescriptor\"];\n};\n\nexport type VfuncRegistry = Record<string, VfuncDescriptor<\"class\"> | VfuncDescriptor<\"interface\">>;\n\nconst classRegistry = new Map<bigint, AnyClass>();\nconst interfaceMixinRegistry = new Map<bigint, Mixin>();\nconst composedClassRegistry = new Map<bigint, AnyClass>();\nconst handleMap = new WeakMap<object, ExternalObject<Handle>>();\nconst vfuncRegistry = new WeakMap<object, VfuncRegistry>();\nconst interfaceVfuncRegistry = new Map<bigint, VfuncRegistry>();\n\nfunction setClassType(cls: AnyClass, type: bigint): void {\n (cls.prototype as { [K in keyof TypedClass]: TypedClass[K] }).__type__ = type;\n}\n\nexport function getClassType(cls: AnyClass): bigint {\n const proto: object = cls.prototype;\n return Object.hasOwn(proto, \"__type__\") ? (proto as TypedClass).__type__ : TYPE_INVALID;\n}\n\n/** Returns the GType tag of the given wrapper instance. */\nexport function getInstanceType(instance: object): bigint {\n return getClassType(instance.constructor as AnyClass);\n}\n\nexport function registerClassType(cls: AnyClass, type: bigint): void {\n if (type !== TYPE_INVALID) {\n classRegistry.set(type, cls);\n setClassType(cls, type);\n }\n}\n\n/**\n * Registers a wrapper class as the JS representation of a GType, optionally\n * installing a registry of virtual functions.\n * @param cls Wrapper class to associate with the type.\n * @param type GType the class wraps.\n * @param vfuncs Virtual functions the class overrides.\n */\nexport function registerWrapperClass(cls: AnyClass, type: bigint, vfuncs?: VfuncRegistry): void {\n registerClassType(cls, type);\n if (vfuncs) registerVfuncRegistry(cls, vfuncs);\n}\n\n/**\n * Registers a GInterface, associating its GType with a mixin used to compose the\n * interface onto wrapper classes and an optional virtual function registry.\n * @param cls Class carrying the interface's GType tag.\n * @param type GType of the interface.\n * @param mixin Mixin that applies the interface to a wrapper class.\n * @param vfuncs Virtual functions the interface exposes.\n */\nexport function registerInterface(cls: AnyClass, type: bigint, mixin: Mixin, vfuncs?: VfuncRegistry): void {\n if (type === TYPE_INVALID) return;\n setClassType(cls, type);\n interfaceMixinRegistry.set(type, mixin);\n if (vfuncs) registerInterfaceVfuncRegistry(type, vfuncs);\n}\n\n/**\n * Wraps a native handle in a JS wrapper instance. With no class, resolves and\n * reuses the wrapper for the handle's runtime GType (composing interface mixins);\n * with an explicit class, creates a bare instance backed by the handle. Returns\n * null for a null or undefined handle.\n * @param handle Native handle to wrap.\n * @param cls Wrapper class to instantiate, or omitted to resolve it from the runtime type.\n */\nexport function wrapHandle(handle: null | undefined, cls?: AnyClass): null;\nexport function wrapHandle<T extends object>(handle: ExternalObject<Handle>, cls: AnyClass<T>): T;\nexport function wrapHandle<T extends object>(\n handle: ExternalObject<Handle> | null | undefined,\n cls: AnyClass<T>,\n): T | null;\nexport function wrapHandle<T extends object = TypedClass>(handle: ExternalObject<Handle>, cls?: AnyClass): T;\nexport function wrapHandle<T extends object = TypedClass>(\n handle: ExternalObject<Handle> | null | undefined,\n cls?: AnyClass,\n): T | null;\nexport function wrapHandle(handle: ExternalObject<Handle> | null | undefined, cls?: AnyClass): object | null {\n if (handle === null || handle === undefined) return null;\n if (cls === undefined) {\n return getOrCreateWrapper(handle);\n }\n const instance: object = Object.create(cls.prototype);\n setHandle(instance, handle);\n return instance;\n}\n\n/**\n * Returns the wrapper class registered for a GType, walking up to ancestor types,\n * and throws if none is registered.\n */\nexport function getWrapperClass(type: bigint): AnyClass {\n const cls = resolveWrapperClass(type);\n if (!cls) {\n throw new Error(`No registered wrapper class for type '${typeName(type) ?? String(type)}'`);\n }\n return cls;\n}\n\nexport function resolveWrapperClass(type: bigint): AnyClass | null {\n let currentType = type;\n while (currentType !== TYPE_INVALID) {\n const cls = classRegistry.get(currentType);\n if (cls) return cls;\n currentType = typeParent(currentType);\n }\n return null;\n}\n\nfunction createComposedClass(base: AnyClass, runtimeType: bigint): AnyClass {\n const baseType = getClassType(base);\n const applied = new Set<bigint>();\n let cls: AnyClass = base;\n for (const type of typeInterfaces(runtimeType)) {\n if (applied.has(type) || typeIsA(baseType, type)) continue;\n const mixin = interfaceMixinRegistry.get(type);\n if (mixin === undefined) continue;\n applied.add(type);\n cls = mixin(cls as AnyClass<MixinReceiver>);\n }\n return applied.size === 0 ? base : cls;\n}\n\nfunction resolveComposedClass(runtimeType: bigint): AnyClass | null {\n const exact = classRegistry.get(runtimeType);\n if (exact) return exact;\n const cached = composedClassRegistry.get(runtimeType);\n if (cached) return cached;\n const base = resolveWrapperClass(runtimeType);\n if (base === null) return null;\n const composed = createComposedClass(base, runtimeType);\n if (composed === base) return base;\n setClassType(composed, runtimeType);\n composedClassRegistry.set(runtimeType, composed);\n return composed;\n}\n\nfunction getOrCreateWrapper(handle: ExternalObject<Handle>): object {\n const existing = getWrapper(handle);\n if (existing) return existing;\n\n const runtimeType: bigint = getType(handle);\n if (runtimeType === TYPE_INVALID) {\n throw new Error(\"Cannot resolve runtime GLib type from handle\");\n }\n\n const cls = resolveComposedClass(runtimeType);\n if (!cls) throw new Error(`Expected registered GLib type, got type ${String(runtimeType)}`);\n const instance: object = Object.create(cls.prototype);\n registerWrapper(handle, instance);\n return instance;\n}\n\n/** Returns the native handle bound to a wrapper instance, throwing if none is set. */\nexport function getHandle(instance: object): ExternalObject<Handle> {\n const handle = handleMap.get(instance);\n if (handle === undefined) {\n const name = (instance as { constructor?: { name?: string } }).constructor?.name ?? \"object\";\n throw new Error(`No native handle associated with ${name}`);\n }\n return handle;\n}\n\n/** Returns the native handle bound to an instance, or undefined when there is none or the instance is null. */\nexport function tryGetHandle(instance: object | null | undefined): ExternalObject<Handle> | undefined {\n return instance == null ? undefined : handleMap.get(instance);\n}\n\n/** Associates a native handle with a wrapper instance. */\nexport function setHandle(instance: object, handle: ExternalObject<Handle>): void {\n handleMap.set(instance, handle);\n}\n\nfunction registerWrapper(handle: ExternalObject<Handle>, instance: object): void {\n setHandle(instance, handle);\n setWrapper(handle, instance);\n}\n\nfunction registerVfuncRegistry(cls: object, registry: VfuncRegistry): void {\n vfuncRegistry.set(cls, registry);\n}\n\nexport function getVfuncRegistry(cls: object): VfuncRegistry | undefined {\n return vfuncRegistry.get(cls);\n}\n\nfunction registerInterfaceVfuncRegistry(type: bigint, registry: VfuncRegistry): void {\n if (type === TYPE_INVALID) return;\n interfaceVfuncRegistry.set(type, registry);\n}\n\nexport function getInterfaceVfuncRegistry(type: bigint): VfuncRegistry | undefined {\n return interfaceVfuncRegistry.get(type);\n}\n"]}
@@ -0,0 +1,34 @@
1
+ import type { Descriptor } from "@gtkx/native";
2
+ import { type Arg } from "./arg.js";
3
+ import { type CallbackDescriptor } from "./descriptors.js";
4
+ /** Function invoked when a connected GObject signal is emitted. */
5
+ export type SignalHandler = (...args: unknown[]) => unknown;
6
+ type SignalConnectSpec = {
7
+ callback: CallbackDescriptor;
8
+ handler: SignalHandler;
9
+ after: boolean;
10
+ };
11
+ type EmitArg = Arg & {
12
+ value?: unknown;
13
+ };
14
+ /** Returns the signal name without its detail suffix (the part after `::`). */
15
+ export declare const getSignalBaseName: (signal: string) => string;
16
+ /**
17
+ * Connects a handler to a GObject signal on an instance and returns the handler id.
18
+ * @param instance Emitter to connect to.
19
+ * @param signal Signal name, optionally including a `::detail` suffix.
20
+ * @param spec Callback descriptor, handler function, and whether to run after the default handler.
21
+ */
22
+ export declare function connectSignal(instance: object, signal: string, spec: SignalConnectSpec): number;
23
+ export declare function blockMatchedSignalHandlers(instance: object, signal: string): void;
24
+ /**
25
+ * Emits a signal on an instance with the given arguments and returns its result
26
+ * combined with any output-argument values.
27
+ * @param instance Emitter to emit the signal on.
28
+ * @param signal Signal name, optionally including a `::detail` suffix.
29
+ * @param args Arguments to pass, including output and inout arguments.
30
+ * @param returnDescriptor Descriptor for the signal's return value, omitted when it returns void.
31
+ */
32
+ export declare function emitSignal(instance: object, signal: string, args: EmitArg[], returnDescriptor?: Descriptor): unknown;
33
+ export {};
34
+ //# sourceMappingURL=signal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signal.d.ts","sourceRoot":"","sources":["../src/signal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA0B,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,KAAK,GAAG,EAAiD,MAAM,UAAU,CAAC;AAGnF,OAAO,EAGH,KAAK,kBAAkB,EAM1B,MAAM,kBAAkB,CAAC;AAe1B,mEAAmE;AACnE,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;AAE5D,KAAK,iBAAiB,GAAG;IACrB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,KAAK,OAAO,GAAG,GAAG,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAoBzC,+EAA+E;AAC/E,eAAO,MAAM,iBAAiB,WAAY,MAAM,KAAG,MAGlD,CAAC;AAwBF;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAM/F;AAED,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAGjF;AAYD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,gBAAgB,CAAC,EAAE,UAAU,GAAG,OAAO,CA6BpH"}
package/dist/signal.js ADDED
@@ -0,0 +1,88 @@
1
+ import { isCallerAllocatedArg, isInoutArg, isOutputArg } from "./arg.js";
2
+ import { bind, createBindCache } from "./bind.js";
3
+ import { wrapCallback } from "./callback.js";
4
+ import { arrayT, biguint64T, objectT, stringT, uint32T, uint64T, voidT, } from "./descriptors.js";
5
+ import { LIB, VALUE_SIZE, VALUE_T } from "./library.js";
6
+ import { getHandle } from "./registry.js";
7
+ import { packTupleResult } from "./tuple.js";
8
+ import { fromValue, getBoxedValue, inoutValueForBoxedDescriptor, newValueForDescriptor, outValueForBoxedDescriptor, outValueForDescriptor, toValue, } from "./value.js";
9
+ const connectCache = createBindCache();
10
+ const gQuarkFromString = bind(LIB, "g_quark_from_string", [stringT("borrowed")], uint32T);
11
+ const gSignalLookup = bind(LIB, "g_signal_lookup", [stringT("borrowed"), biguint64T], uint32T);
12
+ const gSignalEmitv = bind(LIB, "g_signal_emitv", [arrayT(VALUE_T, "array", "borrowed", { elementSize: VALUE_SIZE }), uint32T, uint32T, VALUE_T], voidT);
13
+ const gSignalHandlersBlockMatched = bind(LIB, "g_signal_handlers_block_matched", [objectT("borrowed"), uint32T, uint32T, uint32T, objectT("borrowed"), objectT("borrowed"), objectT("borrowed")], uint32T);
14
+ /** Returns the signal name without its detail suffix (the part after `::`). */
15
+ export const getSignalBaseName = (signal) => {
16
+ const detailIndex = signal.indexOf("::");
17
+ return detailIndex === -1 ? signal : signal.slice(0, detailIndex);
18
+ };
19
+ function getQuarkForSignalDetail(signal) {
20
+ const detailIndex = signal.indexOf("::");
21
+ if (detailIndex === -1)
22
+ return 0;
23
+ return gQuarkFromString(signal.slice(detailIndex + 2));
24
+ }
25
+ const getSignalId = (instance, signal) => {
26
+ const type = instance.__type__;
27
+ return gSignalLookup(getSignalBaseName(signal), type);
28
+ };
29
+ function connectBind(type, signal, callback) {
30
+ const key = `${type}\0${getSignalBaseName(signal)}`;
31
+ return connectCache(key, LIB, "g_signal_connect_data", [objectT("borrowed"), stringT("borrowed"), callback, uint32T], uint64T);
32
+ }
33
+ /**
34
+ * Connects a handler to a GObject signal on an instance and returns the handler id.
35
+ * @param instance Emitter to connect to.
36
+ * @param signal Signal name, optionally including a `::detail` suffix.
37
+ * @param spec Callback descriptor, handler function, and whether to run after the default handler.
38
+ */
39
+ export function connectSignal(instance, signal, spec) {
40
+ const { callback, handler, after } = spec;
41
+ const wrapped = wrapCallback(handler, callback, "emitter");
42
+ const type = instance.__type__;
43
+ const connect = connectBind(type, signal, callback);
44
+ return connect(getHandle(instance), signal, wrapped, after ? 1 : 0);
45
+ }
46
+ export function blockMatchedSignalHandlers(instance, signal) {
47
+ const signalId = getSignalId(instance, signal);
48
+ gSignalHandlersBlockMatched(getHandle(instance), 1, signalId, 0, undefined, undefined, undefined);
49
+ }
50
+ const createEmitValue = (arg) => {
51
+ if (!isOutputArg(arg))
52
+ return { value: toValue(arg.type, arg.value) };
53
+ if (isCallerAllocatedArg(arg)) {
54
+ if (isInoutArg(arg))
55
+ return { value: inoutValueForBoxedDescriptor(arg.type, arg.value) };
56
+ const value = outValueForBoxedDescriptor(arg.type, arg.value);
57
+ return { value, read: () => getBoxedValue(value) };
58
+ }
59
+ return isInoutArg(arg) ? outValueForDescriptor(arg.type, arg.value) : outValueForDescriptor(arg.type);
60
+ };
61
+ /**
62
+ * Emits a signal on an instance with the given arguments and returns its result
63
+ * combined with any output-argument values.
64
+ * @param instance Emitter to emit the signal on.
65
+ * @param signal Signal name, optionally including a `::detail` suffix.
66
+ * @param args Arguments to pass, including output and inout arguments.
67
+ * @param returnDescriptor Descriptor for the signal's return value, omitted when it returns void.
68
+ */
69
+ export function emitSignal(instance, signal, args, returnDescriptor) {
70
+ const signalId = getSignalId(instance, signal);
71
+ const detail = getQuarkForSignalDetail(signal);
72
+ const values = [toValue(objectT("full"), instance)];
73
+ const reads = [];
74
+ for (const arg of args) {
75
+ const { value, read } = createEmitValue(arg);
76
+ values.push(value);
77
+ if (read)
78
+ reads.push(read);
79
+ }
80
+ if (returnDescriptor !== undefined) {
81
+ const returnValue = newValueForDescriptor(returnDescriptor);
82
+ gSignalEmitv(values, signalId, detail, returnValue);
83
+ return packTupleResult(reads.map((read) => read()), fromValue(returnValue), true);
84
+ }
85
+ gSignalEmitv(values, signalId, detail, undefined);
86
+ return packTupleResult(reads.map((read) => read()), undefined, false);
87
+ }
88
+ //# sourceMappingURL=signal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signal.js","sourceRoot":"","sources":["../src/signal.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Descriptor, ExternalObject, Handle } from \"@gtkx/native\";\nimport { type Arg, isCallerAllocatedArg, isInoutArg, isOutputArg } from \"./arg.js\";\nimport { bind, createBindCache } from \"./bind.js\";\nimport { wrapCallback } from \"./callback.js\";\nimport {\n arrayT,\n biguint64T,\n type CallbackDescriptor,\n objectT,\n stringT,\n uint32T,\n uint64T,\n voidT,\n} from \"./descriptors.js\";\nimport { LIB, VALUE_SIZE, VALUE_T } from \"./library.js\";\nimport { getHandle } from \"./registry.js\";\nimport { packTupleResult } from \"./tuple.js\";\nimport type { TypedClass } from \"./type.js\";\nimport {\n fromValue,\n getBoxedValue,\n inoutValueForBoxedDescriptor,\n newValueForDescriptor,\n outValueForBoxedDescriptor,\n outValueForDescriptor,\n toValue,\n} from \"./value.js\";\n\n/** Function invoked when a connected GObject signal is emitted. */\nexport type SignalHandler = (...args: unknown[]) => unknown;\n\ntype SignalConnectSpec = {\n callback: CallbackDescriptor;\n handler: SignalHandler;\n after: boolean;\n};\n\ntype EmitArg = Arg & { value?: unknown };\n\nconst connectCache = createBindCache();\nconst gQuarkFromString = bind(LIB, \"g_quark_from_string\", [stringT(\"borrowed\")], uint32T);\nconst gSignalLookup = bind(LIB, \"g_signal_lookup\", [stringT(\"borrowed\"), biguint64T], uint32T);\n\nconst gSignalEmitv = bind(\n LIB,\n \"g_signal_emitv\",\n [arrayT(VALUE_T, \"array\", \"borrowed\", { elementSize: VALUE_SIZE }), uint32T, uint32T, VALUE_T],\n voidT,\n);\n\nconst gSignalHandlersBlockMatched = bind(\n LIB,\n \"g_signal_handlers_block_matched\",\n [objectT(\"borrowed\"), uint32T, uint32T, uint32T, objectT(\"borrowed\"), objectT(\"borrowed\"), objectT(\"borrowed\")],\n uint32T,\n);\n\n/** Returns the signal name without its detail suffix (the part after `::`). */\nexport const getSignalBaseName = (signal: string): string => {\n const detailIndex = signal.indexOf(\"::\");\n return detailIndex === -1 ? signal : signal.slice(0, detailIndex);\n};\n\nfunction getQuarkForSignalDetail(signal: string): number {\n const detailIndex = signal.indexOf(\"::\");\n if (detailIndex === -1) return 0;\n return gQuarkFromString(signal.slice(detailIndex + 2)) as number;\n}\n\nconst getSignalId = (instance: object, signal: string): number => {\n const type: bigint = (instance as TypedClass).__type__;\n return gSignalLookup(getSignalBaseName(signal), type) as number;\n};\n\nfunction connectBind(type: bigint, signal: string, callback: CallbackDescriptor): (...values: unknown[]) => unknown {\n const key = `${type}\\0${getSignalBaseName(signal)}`;\n return connectCache(\n key,\n LIB,\n \"g_signal_connect_data\",\n [objectT(\"borrowed\"), stringT(\"borrowed\"), callback, uint32T],\n uint64T,\n );\n}\n\n/**\n * Connects a handler to a GObject signal on an instance and returns the handler id.\n * @param instance Emitter to connect to.\n * @param signal Signal name, optionally including a `::detail` suffix.\n * @param spec Callback descriptor, handler function, and whether to run after the default handler.\n */\nexport function connectSignal(instance: object, signal: string, spec: SignalConnectSpec): number {\n const { callback, handler, after } = spec;\n const wrapped = wrapCallback(handler, callback, \"emitter\");\n const type: bigint = (instance as TypedClass).__type__;\n const connect = connectBind(type, signal, callback);\n return connect(getHandle(instance), signal, wrapped, after ? 1 : 0) as number;\n}\n\nexport function blockMatchedSignalHandlers(instance: object, signal: string): void {\n const signalId = getSignalId(instance, signal);\n gSignalHandlersBlockMatched(getHandle(instance), 1, signalId, 0, undefined, undefined, undefined);\n}\n\nconst createEmitValue = (arg: EmitArg): { value: ExternalObject<Handle>; read?: () => unknown } => {\n if (!isOutputArg(arg)) return { value: toValue(arg.type, arg.value) };\n if (isCallerAllocatedArg(arg)) {\n if (isInoutArg(arg)) return { value: inoutValueForBoxedDescriptor(arg.type, arg.value as object) };\n const value = outValueForBoxedDescriptor(arg.type, arg.value as object);\n return { value, read: () => getBoxedValue(value) };\n }\n return isInoutArg(arg) ? outValueForDescriptor(arg.type, arg.value) : outValueForDescriptor(arg.type);\n};\n\n/**\n * Emits a signal on an instance with the given arguments and returns its result\n * combined with any output-argument values.\n * @param instance Emitter to emit the signal on.\n * @param signal Signal name, optionally including a `::detail` suffix.\n * @param args Arguments to pass, including output and inout arguments.\n * @param returnDescriptor Descriptor for the signal's return value, omitted when it returns void.\n */\nexport function emitSignal(instance: object, signal: string, args: EmitArg[], returnDescriptor?: Descriptor): unknown {\n const signalId = getSignalId(instance, signal);\n const detail = getQuarkForSignalDetail(signal);\n const values: ExternalObject<Handle>[] = [toValue(objectT(\"full\"), instance)];\n const reads: (() => unknown)[] = [];\n\n for (const arg of args) {\n const { value, read } = createEmitValue(arg);\n values.push(value);\n if (read) reads.push(read);\n }\n\n if (returnDescriptor !== undefined) {\n const returnValue = newValueForDescriptor(returnDescriptor);\n gSignalEmitv(values, signalId, detail, returnValue);\n return packTupleResult(\n reads.map((read) => read()),\n fromValue(returnValue),\n true,\n );\n }\n\n gSignalEmitv(values, signalId, detail, undefined);\n\n return packTupleResult(\n reads.map((read) => read()),\n undefined,\n false,\n );\n}\n"]}