@gtkx/runtime 1.2.2 → 1.3.0

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 (91) hide show
  1. package/README.md +2 -1
  2. package/dist/arg.d.ts +6 -1
  3. package/dist/arg.d.ts.map +1 -1
  4. package/dist/arg.js +2 -1
  5. package/dist/arg.js.map +1 -1
  6. package/dist/closure.d.ts.map +1 -1
  7. package/dist/closure.js +2 -11
  8. package/dist/closure.js.map +1 -1
  9. package/dist/descriptors.d.ts +21 -3
  10. package/dist/descriptors.d.ts.map +1 -1
  11. package/dist/descriptors.js +50 -21
  12. package/dist/descriptors.js.map +1 -1
  13. package/dist/fn.d.ts +2 -0
  14. package/dist/fn.d.ts.map +1 -1
  15. package/dist/fn.js +50 -10
  16. package/dist/fn.js.map +1 -1
  17. package/dist/index.d.ts +11 -5
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +10 -4
  20. package/dist/index.js.map +1 -1
  21. package/dist/mixin.d.ts +2 -1
  22. package/dist/mixin.d.ts.map +1 -1
  23. package/dist/mixin.js +1 -1
  24. package/dist/mixin.js.map +1 -1
  25. package/dist/native-value.d.ts +9 -3
  26. package/dist/native-value.d.ts.map +1 -1
  27. package/dist/native-value.js +86 -9
  28. package/dist/native-value.js.map +1 -1
  29. package/dist/object.d.ts +14 -6
  30. package/dist/object.d.ts.map +1 -1
  31. package/dist/object.js +21 -10
  32. package/dist/object.js.map +1 -1
  33. package/dist/param-spec.d.ts +31 -1
  34. package/dist/param-spec.d.ts.map +1 -1
  35. package/dist/param-spec.js +66 -5
  36. package/dist/param-spec.js.map +1 -1
  37. package/dist/promisify.d.ts +13 -1
  38. package/dist/promisify.d.ts.map +1 -1
  39. package/dist/promisify.js +14 -1
  40. package/dist/promisify.js.map +1 -1
  41. package/dist/properties.d.ts +28 -1
  42. package/dist/properties.d.ts.map +1 -1
  43. package/dist/properties.js +139 -8
  44. package/dist/properties.js.map +1 -1
  45. package/dist/regex.d.ts +25 -0
  46. package/dist/regex.d.ts.map +1 -0
  47. package/dist/regex.js +59 -0
  48. package/dist/regex.js.map +1 -0
  49. package/dist/register-class.d.ts +154 -11
  50. package/dist/register-class.d.ts.map +1 -1
  51. package/dist/register-class.js +157 -19
  52. package/dist/register-class.js.map +1 -1
  53. package/dist/registry.d.ts +48 -4
  54. package/dist/registry.d.ts.map +1 -1
  55. package/dist/registry.js +147 -3
  56. package/dist/registry.js.map +1 -1
  57. package/dist/signal.d.ts +8 -1
  58. package/dist/signal.d.ts.map +1 -1
  59. package/dist/signal.js +41 -3
  60. package/dist/signal.js.map +1 -1
  61. package/dist/type.d.ts +2 -1
  62. package/dist/type.d.ts.map +1 -1
  63. package/dist/type.js +5 -1
  64. package/dist/type.js.map +1 -1
  65. package/dist/value.d.ts +48 -4
  66. package/dist/value.d.ts.map +1 -1
  67. package/dist/value.js +172 -16
  68. package/dist/value.js.map +1 -1
  69. package/dist/variant.d.ts +75 -26
  70. package/dist/variant.d.ts.map +1 -1
  71. package/dist/variant.js +44 -29
  72. package/dist/variant.js.map +1 -1
  73. package/package.json +4 -4
  74. package/src/arg.ts +6 -1
  75. package/src/closure.ts +2 -14
  76. package/src/descriptors.ts +74 -21
  77. package/src/fn.ts +73 -17
  78. package/src/index.ts +31 -4
  79. package/src/mixin.ts +1 -1
  80. package/src/native-value.ts +146 -14
  81. package/src/object.ts +23 -11
  82. package/src/param-spec.ts +94 -8
  83. package/src/promisify.ts +27 -1
  84. package/src/properties.ts +184 -5
  85. package/src/regex.ts +92 -0
  86. package/src/register-class.ts +446 -38
  87. package/src/registry.ts +219 -4
  88. package/src/signal.ts +77 -0
  89. package/src/type.ts +7 -0
  90. package/src/value.ts +268 -14
  91. package/src/variant.ts +184 -53
@@ -1,5 +1,6 @@
1
1
  import { type AnyClass } from "@gtkx/utils";
2
2
  import { type PropertySpec } from "./properties.js";
3
+ import { type TypedClass } from "./type.js";
3
4
  /**
4
5
  * A generated interface value, such as `Gio.ListModel`, in the form {@link registerClass} takes it.
5
6
  * `__impl__` exists only in the type system: it carries the interface's `Impl` type, of which a class
@@ -31,13 +32,48 @@ type Camelized<TName extends string> = TName extends `${infer THead}-${infer TTa
31
32
  * type and names nothing, because a name only known as `string` addresses no member in particular.
32
33
  */
33
34
  type InstalledNames<TProperties> = string extends keyof TProperties ? never : Camelized<Dashed<keyof TProperties & string>>;
35
+ /**
36
+ * The base names the signal surface takes for the signals `RegisterClassOptions.signals` declares:
37
+ * each name as written, plus its canonical spelling with underscores turned into dashes, which
38
+ * GObject knows the signal by too.
39
+ */
40
+ type DeclaredSignalBase<TSignals> = (keyof TSignals & string) | Dashed<keyof TSignals & string>;
41
+ /**
42
+ * The names `connect` and `emit` take for one of the signals `RegisterClassOptions.signals`
43
+ * declares: each spelling of each name, plus its detailed form for a signal emitted with a
44
+ * `::detail` suffix.
45
+ */
46
+ type DeclaredSignalName<TSignals> = DeclaredSignalBase<TSignals> | `${DeclaredSignalBase<TSignals>}::${string}`;
47
+ /**
48
+ * The `connect` and `emit` signatures instances gain for the signals
49
+ * `RegisterClassOptions.signals` declares, widening the inherited ones, which take only the names
50
+ * introspection knows. A class declaring no signals gains nothing, since no name reaches the
51
+ * added signatures.
52
+ */
53
+ type DeclaredSignalMethods<TSignals> = {
54
+ /**
55
+ * Type-level map from declared signal name to handler signature, feeding the hooks that
56
+ * address a signal by name, such as `useSignal` from `@gtkx/react`; no value ever carries it.
57
+ */
58
+ __signals__?: Record<DeclaredSignalBase<TSignals>, (...args: never[]) => unknown>;
59
+ /** Connects a handler to a signal `RegisterClassOptions.signals` declared. */
60
+ connect(signal: DeclaredSignalName<TSignals>, handler: (...args: never[]) => unknown, isAfter?: boolean): number;
61
+ /** Emits a signal `RegisterClassOptions.signals` declared. */
62
+ emit(sigName: DeclaredSignalName<TSignals>, ...args: unknown[]): unknown;
63
+ /** Connects a handler to a signal `RegisterClassOptions.signals` declared, for `off` to take off. */
64
+ on(sigName: DeclaredSignalName<TSignals>, callback: (...args: unknown[]) => unknown, isAfter?: boolean): unknown;
65
+ /** Connects a handler to a signal `RegisterClassOptions.signals` declared for one emission. */
66
+ once(sigName: DeclaredSignalName<TSignals>, callback: (...args: unknown[]) => unknown, isAfter?: boolean): unknown;
67
+ /** Disconnects a handler `on` or `once` connected to a signal `RegisterClassOptions.signals` declared. */
68
+ off(sigName: DeclaredSignalName<TSignals>, callback: (...args: unknown[]) => unknown): unknown;
69
+ };
34
70
  /**
35
71
  * An instance of a registered class: everything the class itself declares, plus the property map the
36
72
  * hooks that address a property by name, such as `useProperty` from `@gtkx/react`, read the installed
37
73
  * names off. Each name is typed with the value type the class declares for the member of that name,
38
74
  * so a property the class does not `declare` contributes nothing.
39
75
  */
40
- type RegisteredInstance<TInstance, TProperties> = TInstance & {
76
+ type RegisteredInstance<TInstance, TProperties, TSignals> = TInstance & DeclaredSignalMethods<TSignals> & {
41
77
  /** Type-level map from installed property name to value type; no value ever carries it. */
42
78
  __properties__: Pick<TInstance, InstalledNames<TProperties> & keyof TInstance>;
43
79
  };
@@ -50,16 +86,79 @@ type RegisteredConstructor<TClass, TArgs extends unknown[], TInstance> = {
50
86
  /** Object the class's instances inherit from. */
51
87
  prototype: TInstance;
52
88
  } & (TClass extends new (...args: never) => unknown ? new (...args: TArgs) => TInstance : abstract new (...args: TArgs) => TInstance);
89
+ /** The statics a registered class keeps from the class it was, joined with {@link RegisteredConstructor}. */
90
+ type RegisteredParts<TClass, TArgs extends unknown[], TInstance> = Omit<TClass, "prototype"> & RegisteredConstructor<TClass, TArgs, TInstance>;
53
91
  /**
54
92
  * The class {@link registerClass} hands back: the same class, with the same statics, whose instances
55
- * carry the properties `RegisterClassOptions.properties` installed. Binding the call to a name, rather
56
- * than discarding it, is what carries those names into the type system.
93
+ * carry the properties `RegisterClassOptions.properties` installed and take the signals
94
+ * `RegisterClassOptions.signals` declares by name. Binding the call to a name, rather than
95
+ * discarding it, is what carries those names into the type system.
96
+ */
97
+ type RegisteredClass<TClass extends AnyClass, TProperties, TSignals> = TClass extends abstract new (...args: infer TArgs) => infer TInstance ? RegisteredParts<TClass, TArgs, RegisteredInstance<TInstance, TProperties, TSignals>> : never;
98
+ /**
99
+ * A GType in the form `RegisterClassOptions.signals` takes one: the numeric GType itself, such as
100
+ * `TYPE_STRING` from `@gtkx/gi/gobject`, or a class carrying one, which is any generated wrapper
101
+ * class and any class an earlier {@link registerClass} call registered.
102
+ */
103
+ type SignalGType = bigint | AnyClass<TypedClass>;
104
+ /**
105
+ * One signal `RegisterClassOptions.signals` creates on the new type, sitting under the signal's
106
+ * name. Every part is optional: `{}` declares a signal with no arguments and no return value that
107
+ * runs its handlers in the default `RUN_FIRST` stage.
57
108
  */
58
- type RegisteredClass<TClass extends AnyClass, TProperties> = TClass extends abstract new (...args: infer TArgs) => infer TInstance ? Omit<TClass, "prototype"> & RegisteredConstructor<TClass, TArgs, RegisteredInstance<TInstance, TProperties>> : never;
109
+ type SignalSpec = {
110
+ /**
111
+ * `GObject.SignalFlags` bit mask for the signal, defaulting to `RUN_FIRST`. `DETAILED` lets
112
+ * handlers connect to and emissions name a `::detail` suffix.
113
+ */
114
+ flags?: number;
115
+ /** GType of each argument an emission carries, defaulting to none. */
116
+ paramTypes?: SignalGType[];
117
+ /** GType of the value an emission returns, defaulting to none. */
118
+ returnType?: SignalGType;
119
+ /**
120
+ * How the emission combines what its handlers return, limited to the two accumulators GObject
121
+ * ships: `"first-wins"` stops the emission at the first handler and keeps its result, and
122
+ * `"true-handled"` runs handlers until one returns `true`, which requires a boolean
123
+ * `returnType`. Without one, every handler runs and the last result stands.
124
+ */
125
+ accumulator?: "first-wins" | "true-handled";
126
+ };
59
127
  /** What {@link registerClass} adds to the new GType beyond the vtable slots it discovers on the class. */
60
- type RegisterClassOptions<TInstance extends object, TProperties extends Record<string, PropertySpec>> = {
61
- /** Name to register the new GType under, defaulting to the class's own name. */
128
+ type RegisterClassOptions<TInstance extends object, TProperties extends Record<string, PropertySpec>, TSignals extends Record<string, SignalSpec>> = {
129
+ /**
130
+ * Name to register the new GType under, defaulting to the class's own name. Either way the
131
+ * name has to be a valid GType name: at least three characters, starting with a letter or
132
+ * underscore, the rest letters, digits, `-`, `_` or `+`. Any other name throws a `TypeError`.
133
+ */
62
134
  typeName?: string;
135
+ /**
136
+ * Registers the new GType abstract, the way `G_TYPE_FLAG_ABSTRACT` marks a C type: the class
137
+ * still serves as a parent for further registered subclasses, which instantiate as usual, but
138
+ * constructing it directly throws, whether from JavaScript or from a native caller.
139
+ */
140
+ abstract?: boolean;
141
+ /**
142
+ * Name instances of the new type carry in CSS, applied through `gtk_widget_class_set_css_name`
143
+ * from inside the type's `class_init`, so every instance is born with it, wherever it is
144
+ * created from. Requires the class to extend `Gtk.Widget`; registering a non-widget with a
145
+ * `cssName` throws.
146
+ */
147
+ cssName?: string;
148
+ /**
149
+ * Hook run once, synchronously, while `registerClass` registers the type, after its
150
+ * `class_init` has installed the vfuncs, properties and signals declared here. It receives the
151
+ * new type's class struct wrapped in its generated GTypeStruct wrapper, so class-level setup
152
+ * calls such as `Gtk.WidgetClass.installAction`, `Gtk.WidgetClass.addShortcut` and
153
+ * `Gtk.WidgetClass.setLayoutManagerType` have somewhere to land. The wrapper serves the
154
+ * members of every struct in the parent chain on one object: a widget subclass sees
155
+ * `Gtk.WidgetClass` and `GObject.ObjectClass` members alike, so the parameter can be declared
156
+ * as whichever of those types the hook needs. The class struct belongs to the type system for
157
+ * the life of the process, so keeping the wrapper around past the hook is safe, if rarely
158
+ * useful. An exception the hook throws propagates out of `registerClass`, with the type
159
+ * already registered: GObject offers no way to unregister a static type.
160
+ */
161
+ classInit?(typeStruct: object): void;
63
162
  /**
64
163
  * Interfaces the new type implements on top of the ones it inherits, given as the interface values
65
164
  * themselves, such as `Gio.ListModel`. Their vtable slots are filled from the `vfunc`-prefixed methods on
@@ -123,6 +222,28 @@ type RegisterClassOptions<TInstance extends object, TProperties extends Record<s
123
222
  * and write it rather than the generated storage.
124
223
  */
125
224
  properties?: TProperties;
225
+ /**
226
+ * Signals to create on the new type, keyed by signal name and valued with the
227
+ * {@link SignalSpec} describing each one. A name has to start with a letter, continue in
228
+ * letters, digits, `-` and `_`, and be new to the type: one an ancestor type or a listed
229
+ * interface already carries throws. The two word separators spell the same signal, so a
230
+ * signal declared as `data_changed` is connected to and emitted as `data-changed` too.
231
+ *
232
+ * Instances connect and emit by name through the same `connect`, `on`, `once`, `off` and
233
+ * `emit` surface inherited signals use: `registerClass` wraps `connect` and `emit` on the
234
+ * class's prototype to serve the declared names, unless the class defines the member itself,
235
+ * and hands every other name to the inherited implementation. A handler receives the
236
+ * emission's arguments without the leading emitter, matching a generated signal, and what it
237
+ * returns becomes the emission's return value when the signal declares one.
238
+ *
239
+ * The declared parameter GTypes rule the emission: `emit` takes exactly one argument per
240
+ * declared parameter, throwing a `TypeError` for any other count, and converts each argument
241
+ * into a `GValue` of the declared type, throwing for a value that type cannot hold. The signals
242
+ * are created with no class closure of their own, but a method named `on<SignalName>`
243
+ * becomes the signal's default handler, the way every `on`-prefixed method that names a
244
+ * signal the type carries does; see {@link registerClass}.
245
+ */
246
+ signals?: TSignals;
126
247
  };
127
248
  /**
128
249
  * Registers a subclass of a wrapper class as a new GType, wiring up any class and interface
@@ -130,10 +251,19 @@ type RegisterClassOptions<TInstance extends object, TProperties extends Record<s
130
251
  * `RegisterClassOptions.implements` names.
131
252
  *
132
253
  * Throws when the class does not extend a registered wrapper class, when it has no derivable type
133
- * name, when an entry in `RegisterClassOptions.implements` is not a registered interface, when a
254
+ * name or the name is not a valid GType name, when an entry in
255
+ * `RegisterClassOptions.implements` is not a registered interface, when a
134
256
  * listed interface has a prerequisite that neither the parent type nor another listed interface meets,
135
- * and when an entry in `RegisterClassOptions.properties` names its `GObject.ParamSpec` something other
136
- * than the canonical spelling of the key it sits under.
257
+ * when the list names `Gio.AsyncInitable` as an interface the parent type does not already
258
+ * implement and no method on the chain fills `vfuncInitAsync`, since the default `init_async`
259
+ * would run `vfuncInit` on a worker thread, when an entry in
260
+ * `RegisterClassOptions.properties` names its `GObject.ParamSpec` something other than the canonical
261
+ * spelling of the key it sits under, when an entry in
262
+ * `RegisterClassOptions.signals` carries an invalid name, a name the type already knows, a GType
263
+ * that cannot hold a value, or an accumulator the spec does not admit, and when
264
+ * `RegisterClassOptions.cssName` is
265
+ * given for a class that does not extend `Gtk.Widget`. An exception thrown by
266
+ * `RegisterClassOptions.classInit` also propagates, after the type has already been registered.
137
267
  *
138
268
  * A slot is filled from the `vfunc`-prefixed methods on the class's prototype chain, up to but not
139
269
  * including the registered ancestor the class extends, so a method an intermediate base class
@@ -143,6 +273,19 @@ type RegisterClassOptions<TInstance extends object, TProperties extends Record<s
143
273
  * Declare every slot as a method: a class field holding a function, such as `vfuncGetNItems = () => 1`,
144
274
  * is assigned to each instance after registration and never reaches the vtable.
145
275
  *
276
+ * A method named `on<SignalName>` — the signal's name in camelCase after the `on`, so `onClicked`
277
+ * for `clicked` and `onItemsChanged` for `items-changed` — becomes that signal's default handler
278
+ * when the type carries the signal, whether an ancestor type or an implemented interface brings it
279
+ * or `RegisterClassOptions.signals` declares it. The method is installed as a class-closure
280
+ * override, so it runs on every emission, on the instances a native caller creates included, in
281
+ * the stage the signal's flags name rather than alongside connected handlers. It receives the
282
+ * emission's arguments without the leading emitter, with `this` bound to the emitter, and what it
283
+ * returns becomes the emission's result when the signal declares one. The same discovery walks the
284
+ * prototype chain vfunc discovery walks, and a subclass registering its own `on<SignalName>`
285
+ * replaces the handler for its instances, where `super.on<SignalName>()` reaches the replaced one.
286
+ * An `on`-prefixed method naming no signal the type carries is left alone as the ordinary method
287
+ * it is.
288
+ *
146
289
  * An override of `vfuncConstructed` runs from inside the base constructor, before JavaScript
147
290
  * installs the subclass's field initializers and runs its constructor body, so a field still
148
291
  * reads `undefined` there and reading a `#private` field throws. Declare state the override
@@ -155,6 +298,6 @@ type RegisterClassOptions<TInstance extends object, TProperties extends Record<s
155
298
  * @param options What the new GType gains beyond the vtable slots the class overrides.
156
299
  * @returns The same class, now registered, with every name in `options.properties` in its property map.
157
300
  */
158
- declare function registerClass<T extends AnyClass, TProperties extends Record<string, PropertySpec> = Record<never, PropertySpec>>(klass: T, options?: RegisterClassOptions<T["prototype"], TProperties>): RegisteredClass<T, TProperties>;
159
- export { type Interface, registerClass };
301
+ declare function registerClass<T extends AnyClass, TProperties extends Record<string, PropertySpec> = Record<never, PropertySpec>, TSignals extends Record<string, SignalSpec> = Record<never, SignalSpec>>(klass: T, options?: RegisterClassOptions<T["prototype"], TProperties, TSignals>): RegisteredClass<T, TProperties, TSignals>;
302
+ export { type Interface, registerClass, type SignalGType, type SignalSpec };
160
303
  //# sourceMappingURL=register-class.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"register-class.d.ts","sourceRoot":"","sources":["../src/register-class.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"register-class.d.ts","sourceRoot":"","sources":["../src/register-class.ts"],"names":[],"mappings":"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"}
@@ -1,32 +1,37 @@
1
1
  import { registerClass as nativeRegisterClass, } from "@gtkx/native";
2
- import { getParentClass, walkClassChain } from "@gtkx/utils";
2
+ import { getParentClass, kebabCase, walkClassChain } from "@gtkx/utils";
3
3
  import { wrapCallback } from "./callback.js";
4
4
  import { insertMixinLayer } from "./mixin.js";
5
5
  import { buildPropertyDispatch, GET_PROPERTY_VFUNC, makeGetProperty, makeSetProperty, SET_PROPERTY_VFUNC, toNativeProperties, } from "./properties.js";
6
- import { getClassType, getInterfaceMixin, markDerivedClass, registerClassType, } from "./registry.js";
7
- import { TYPE_INTERFACE, TYPE_INVALID, typeFundamental, typeInterfaces, typeIsA } from "./type.js";
6
+ import { getClassStructClass, getClassType, getInterfaceMixin, getTypeClassHandle, markDerivedClass, registerClassType, wrapHandle, } from "./registry.js";
7
+ import { connectClosureSignal, emitDeclaredSignal, getSignalBaseName, overrideSignalClassClosure, } from "./signal.js";
8
+ import { TYPE_INTERFACE, TYPE_INVALID, TYPE_NONE, typeFundamental, typeInterfaces, typeIsA, typeName, } from "./type.js";
8
9
  import { findClassVfuncDescriptor, findInterfaceVfuncDescriptor } from "./vfunc.js";
9
10
  const INSTANCE_ARG_INDEX = 0;
10
11
  const VALUE_ARG_INDEX = 2;
11
12
  const TEARDOWN_VFUNC_NAMES = new Set(["dispose", "finalize"]);
13
+ const ASYNC_INITABLE_TYPE_NAME = "GAsyncInitable";
14
+ const INIT_ASYNC_METHOD_NAME = "vfuncInitAsync";
12
15
  const PROPERTY_VFUNC_SPECS = [
13
16
  { methodName: GET_PROPERTY_VFUNC, isValueOut: true, makeDispatch: makeGetProperty },
14
17
  { methodName: SET_PROPERTY_VFUNC, isValueOut: false, makeDispatch: makeSetProperty },
15
18
  ];
16
19
  const PROPERTY_VFUNC_NAMES = new Set(PROPERTY_VFUNC_SPECS.map((spec) => spec.methodName));
20
+ const TYPE_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9\-_+]{2,}$/;
21
+ const SIGNAL_OVERRIDE_PATTERN = /^on[A-Z]/;
17
22
  function registerClass(klass, options = {}) {
18
23
  const parentType = resolveParentType(klass);
19
24
  if (parentType === TYPE_INVALID) {
20
25
  throw new TypeError(`registerClass: ${klass.name} must extend a registered wrapper class`);
21
26
  }
22
- const name = options.typeName ?? klass.name;
23
- if (!name) {
24
- throw new Error("registerClass: cannot derive a GType name (anonymous class with no typeName option)");
25
- }
27
+ const name = resolveTypeName(klass, options);
26
28
  const declaredTypes = resolveInterfaceTypes(klass, options.implements ?? []);
27
29
  const adoptedTypes = declaredTypes.filter((gtype) => !typeIsA(parentType, gtype));
28
30
  const properties = options.properties ?? {};
29
- const { methods, inheritedNames } = collectInstanceMembers(klass);
31
+ const signals = resolveDeclaredSignals(klass, options.signals ?? {});
32
+ const members = collectInstanceMembers(klass);
33
+ const { methods, inheritedNames } = members;
34
+ checkAsyncInitable(klass, adoptedTypes, methods);
30
35
  const dispatch = buildPropertyDispatch({ klass, properties, adoptedTypes });
31
36
  const classVfuncs = [
32
37
  ...discoverClassVfuncs(klass, methods),
@@ -34,13 +39,37 @@ function registerClass(klass, options = {}) {
34
39
  ];
35
40
  const claimedMethodNames = new Set(classVfuncs.map((vfunc) => vfunc.methodName));
36
41
  const interfaceBindings = discoverInterfaceBindings(methods, parentType, declaredTypes, claimedMethodNames);
37
- const nativeOptions = toNativeOptions(classVfuncs, interfaceBindings, properties);
42
+ const nativeOptions = withNativeSignals(toNativeOptions(classVfuncs, interfaceBindings, properties, options), signals.native);
38
43
  const newType = nativeRegisterClass(name, parentType, nativeOptions);
39
44
  registerClassType(klass, newType);
40
45
  markDerivedClass(klass);
46
+ installSignalOverrides(newType, methods);
41
47
  applyInterfaceMixins(klass, adoptedTypes, inheritedNames);
48
+ installDeclaredSignalMethods(klass, signals.table, members.names);
49
+ invokeClassInit(options, newType);
42
50
  return klass;
43
51
  }
52
+ function invokeClassInit(options, newType) {
53
+ if (options.classInit === undefined) {
54
+ return;
55
+ }
56
+ const structClass = getClassStructClass(newType);
57
+ if (structClass === undefined) {
58
+ throw new Error("registerClass: no ancestor of the new type registers a class struct wrapper");
59
+ }
60
+ options.classInit(wrapHandle(getTypeClassHandle(newType), structClass));
61
+ }
62
+ function resolveTypeName(klass, options) {
63
+ const name = options.typeName ?? klass.name;
64
+ if (!name) {
65
+ throw new TypeError("registerClass: cannot derive a GType name (anonymous class with no typeName option)");
66
+ }
67
+ if (!TYPE_NAME_PATTERN.test(name)) {
68
+ throw new TypeError(`registerClass: '${name}' is not a valid GType name (a letter or underscore, then at ` +
69
+ "least two more characters, all from A-Z, a-z, 0-9, '-', '_' and '+')");
70
+ }
71
+ return name;
72
+ }
44
73
  function resolveInterfaceType(klass, entry) {
45
74
  const gtype = getClassType(entry);
46
75
  if (typeFundamental(gtype) !== TYPE_INTERFACE) {
@@ -52,6 +81,13 @@ function resolveInterfaceType(klass, entry) {
52
81
  function resolveInterfaceTypes(klass, entries) {
53
82
  return [...new Set(entries.map((entry) => resolveInterfaceType(klass, entry)))];
54
83
  }
84
+ function checkAsyncInitable(klass, adoptedTypes, methods) {
85
+ const isAsyncInitable = adoptedTypes.some((gtype) => typeName(gtype) === ASYNC_INITABLE_TYPE_NAME);
86
+ if (isAsyncInitable && !methods.has(INIT_ASYNC_METHOD_NAME)) {
87
+ throw new TypeError(`registerClass: ${klass.name} implements Gio.AsyncInitable without overriding 'vfuncInitAsync'; ` +
88
+ "the default 'init_async' would run 'vfuncInit' on a worker thread");
89
+ }
90
+ }
55
91
  function applyInterfaceMixins(klass, adoptedTypes, inheritedNames) {
56
92
  for (const gtype of adoptedTypes) {
57
93
  const mixin = getInterfaceMixin(gtype);
@@ -187,6 +223,99 @@ function buildPropertyVfunc(klass, methodName, fn, isValueOut) {
187
223
  fn: wrapVfunc(fn, argDescriptors, descriptor),
188
224
  };
189
225
  }
226
+ const canonicalSignalName = (name) => name.replaceAll("_", "-");
227
+ function installSignalOverrides(newType, methods) {
228
+ for (const [methodName, fn] of methods) {
229
+ if (!SIGNAL_OVERRIDE_PATTERN.test(methodName)) {
230
+ continue;
231
+ }
232
+ const handler = fn;
233
+ overrideSignalClassClosure(newType, kebabCase(methodName.slice(2)), (...args) => handler.apply(args[0], args.slice(1)));
234
+ }
235
+ }
236
+ function resolveSignalGType(klass, signalName, role, entry) {
237
+ if (typeof entry === "bigint") {
238
+ return entry;
239
+ }
240
+ const gtype = getClassType(entry);
241
+ if (gtype === TYPE_INVALID) {
242
+ throw new TypeError(`registerClass: signal '${signalName}' of ${klass.name} names a class with no registered ` +
243
+ `GType as its ${role}`);
244
+ }
245
+ return gtype;
246
+ }
247
+ function resolveSignalReturnType(klass, name, spec) {
248
+ if (spec.returnType === undefined) {
249
+ return undefined;
250
+ }
251
+ const returnType = resolveSignalGType(klass, name, "return type", spec.returnType);
252
+ return returnType === TYPE_NONE ? undefined : returnType;
253
+ }
254
+ function resolveDeclaredSignal(klass, name, spec) {
255
+ const paramTypes = (spec.paramTypes ?? []).map((entry, index) => resolveSignalGType(klass, name, `parameter ${String(index)}`, entry));
256
+ const returnType = resolveSignalReturnType(klass, name, spec);
257
+ const native = { name, paramTypes };
258
+ const declared = { paramTypes };
259
+ if (spec.flags !== undefined) {
260
+ native.flags = spec.flags;
261
+ }
262
+ if (spec.accumulator !== undefined) {
263
+ native.accumulator = spec.accumulator;
264
+ }
265
+ if (returnType !== undefined) {
266
+ native.returnType = returnType;
267
+ declared.returnType = returnType;
268
+ }
269
+ return { native, declared };
270
+ }
271
+ function resolveDeclaredSignals(klass, signals) {
272
+ const native = [];
273
+ const table = new Map();
274
+ for (const [name, spec] of Object.entries(signals)) {
275
+ const resolved = resolveDeclaredSignal(klass, name, spec);
276
+ native.push(resolved.native);
277
+ table.set(canonicalSignalName(name), resolved.declared);
278
+ }
279
+ return { native, table };
280
+ }
281
+ function inheritedSignalMethod(inherited, signal) {
282
+ if (inherited === undefined) {
283
+ throw new Error(`Unknown signal '${signal}'`);
284
+ }
285
+ return inherited;
286
+ }
287
+ function installDeclaredConnect(proto, findDeclared) {
288
+ const inheritedConnect = proto.connect;
289
+ proto.connect = function connect(signal, handler, isAfter) {
290
+ if (findDeclared(signal) === undefined) {
291
+ return inheritedSignalMethod(inheritedConnect, signal).call(this, signal, handler, isAfter);
292
+ }
293
+ return connectClosureSignal(this, signal, handler, isAfter ?? false);
294
+ };
295
+ }
296
+ function installDeclaredEmit(proto, findDeclared) {
297
+ const inheritedEmit = proto.emit;
298
+ proto.emit = function emit(sigName, ...args) {
299
+ const declared = findDeclared(sigName);
300
+ if (declared === undefined) {
301
+ return inheritedSignalMethod(inheritedEmit, sigName).call(this, sigName, ...args);
302
+ }
303
+ return emitDeclaredSignal(this, sigName, declared, args);
304
+ };
305
+ }
306
+ function installDeclaredSignalMethods(klass, table, definedNames) {
307
+ if (table.size === 0) {
308
+ return;
309
+ }
310
+ const proto = klass.prototype;
311
+ const findDeclared = (signal) => table.get(canonicalSignalName(getSignalBaseName(signal)));
312
+ if (!definedNames.has("connect")) {
313
+ installDeclaredConnect(proto, findDeclared);
314
+ }
315
+ if (!definedNames.has("emit")) {
316
+ installDeclaredEmit(proto, findDeclared);
317
+ }
318
+ }
190
319
  function toNativeInterface(binding) {
191
320
  const nativeInterface = {
192
321
  type: binding.gtype,
@@ -198,24 +327,33 @@ function toNativeInterface(binding) {
198
327
  }
199
328
  return nativeInterface;
200
329
  }
201
- function toNativeOptions(classVfuncs, interfaceBindings, properties) {
202
- const hasInterfaces = interfaceBindings.length > 0;
203
- const hasClassVfuncs = classVfuncs.length > 0;
204
- const hasProperties = Object.keys(properties).length > 0;
205
- if (!hasClassVfuncs && !hasInterfaces && !hasProperties) {
206
- return undefined;
330
+ function withNativeSignals(options, signals) {
331
+ if (signals.length === 0) {
332
+ return options;
333
+ }
334
+ return { ...options, signals };
335
+ }
336
+ function applyNativeTypeOptions(options, source) {
337
+ if (source.abstract ?? false) {
338
+ options.abstract = true;
339
+ }
340
+ if (source.cssName !== undefined) {
341
+ options.cssName = source.cssName;
207
342
  }
343
+ }
344
+ function toNativeOptions(classVfuncs, interfaceBindings, properties, source) {
208
345
  const options = {};
209
- if (hasProperties) {
346
+ applyNativeTypeOptions(options, source);
347
+ if (Object.keys(properties).length > 0) {
210
348
  options.properties = toNativeProperties(properties);
211
349
  }
212
- if (hasClassVfuncs) {
350
+ if (classVfuncs.length > 0) {
213
351
  options.vfuncs = [...classVfuncs];
214
352
  }
215
- if (hasInterfaces) {
353
+ if (interfaceBindings.length > 0) {
216
354
  options.interfaces = interfaceBindings.map((binding) => toNativeInterface(binding));
217
355
  }
218
- return options;
356
+ return Object.keys(options).length > 0 ? options : undefined;
219
357
  }
220
358
  export { registerClass };
221
359
  //# sourceMappingURL=register-class.js.map