@gtkx/runtime 1.6.0 → 2.0.0-beta.2
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.
- package/README.md +5 -5
- package/dist/application-class.d.ts +1 -1
- package/dist/application-class.d.ts.map +1 -1
- package/dist/application-class.js +1 -2
- package/dist/application-class.js.map +1 -1
- package/dist/arg.d.ts +4 -1
- package/dist/arg.d.ts.map +1 -1
- package/dist/arg.js.map +1 -1
- package/dist/bind.d.ts.map +1 -1
- package/dist/bind.js +1 -9
- package/dist/bind.js.map +1 -1
- package/dist/callback.d.ts +6 -1
- package/dist/callback.d.ts.map +1 -1
- package/dist/callback.js +33 -21
- package/dist/callback.js.map +1 -1
- package/dist/closure.d.ts +3 -1
- package/dist/closure.d.ts.map +1 -1
- package/dist/closure.js +17 -6
- package/dist/closure.js.map +1 -1
- package/dist/descriptors.d.ts +22 -51
- package/dist/descriptors.d.ts.map +1 -1
- package/dist/descriptors.js +53 -27
- package/dist/descriptors.js.map +1 -1
- package/dist/fn.d.ts.map +1 -1
- package/dist/fn.js +23 -9
- package/dist/fn.js.map +1 -1
- package/dist/folded-lengths.d.ts +2 -1
- package/dist/folded-lengths.d.ts.map +1 -1
- package/dist/folded-lengths.js +17 -7
- package/dist/folded-lengths.js.map +1 -1
- package/dist/index.d.ts +2 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -24
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +18 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +14 -2
- package/dist/internal.js.map +1 -1
- package/dist/listeners.d.ts +3 -13
- package/dist/listeners.d.ts.map +1 -1
- package/dist/listeners.js +12 -12
- package/dist/listeners.js.map +1 -1
- package/dist/mixin.d.ts +5 -3
- package/dist/mixin.d.ts.map +1 -1
- package/dist/mixin.js +36 -9
- package/dist/mixin.js.map +1 -1
- package/dist/native-value.d.ts +9 -1
- package/dist/native-value.d.ts.map +1 -1
- package/dist/native-value.js +20 -3
- package/dist/native-value.js.map +1 -1
- package/dist/object.d.ts +11 -0
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +18 -25
- package/dist/object.js.map +1 -1
- package/dist/properties.d.ts +5 -3
- package/dist/properties.d.ts.map +1 -1
- package/dist/properties.js +67 -23
- package/dist/properties.js.map +1 -1
- package/dist/property-brand.d.ts +5 -0
- package/dist/property-brand.d.ts.map +1 -0
- package/dist/property-brand.js +5 -0
- package/dist/property-brand.js.map +1 -0
- package/dist/register-class.d.ts +142 -264
- package/dist/register-class.d.ts.map +1 -1
- package/dist/register-class.js +19 -37
- package/dist/register-class.js.map +1 -1
- package/dist/registry.d.ts +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +4 -4
- package/dist/registry.js.map +1 -1
- package/dist/signal-brand.d.ts +12 -0
- package/dist/signal-brand.d.ts.map +1 -0
- package/dist/signal-brand.js +6 -0
- package/dist/signal-brand.js.map +1 -0
- package/dist/signal.d.ts +39 -2
- package/dist/signal.d.ts.map +1 -1
- package/dist/signal.js +84 -27
- package/dist/signal.js.map +1 -1
- package/dist/t.d.ts +5 -21
- package/dist/t.d.ts.map +1 -1
- package/dist/t.js +1 -5
- package/dist/t.js.map +1 -1
- package/dist/type.d.ts.map +1 -1
- package/dist/type.js +8 -2
- package/dist/type.js.map +1 -1
- package/dist/value.d.ts.map +1 -1
- package/dist/value.js +7 -1
- package/dist/value.js.map +1 -1
- package/dist/variant.d.ts +2 -6
- package/dist/variant.d.ts.map +1 -1
- package/dist/variant.js.map +1 -1
- package/dist/vfunc-call.d.ts.map +1 -1
- package/dist/vfunc-call.js +2 -11
- package/dist/vfunc-call.js.map +1 -1
- package/package.json +9 -5
- package/src/application-class.ts +2 -2
- package/src/arg.ts +4 -1
- package/src/bind.ts +1 -12
- package/src/callback.ts +53 -29
- package/src/closure.ts +31 -6
- package/src/descriptors.ts +95 -59
- package/src/fn.ts +31 -10
- package/src/folded-lengths.ts +23 -10
- package/src/index.ts +2 -24
- package/src/internal.ts +43 -2
- package/src/listeners.ts +21 -26
- package/src/mixin.ts +55 -9
- package/src/native-value.ts +24 -3
- package/src/object.ts +55 -5
- package/src/properties.ts +90 -26
- package/src/property-brand.ts +5 -0
- package/src/register-class.ts +338 -341
- package/src/registry.ts +4 -4
- package/src/signal-brand.ts +29 -0
- package/src/signal.ts +185 -39
- package/src/t.ts +5 -21
- package/src/type.ts +10 -2
- package/src/value.ts +9 -1
- package/src/variant.ts +2 -6
- package/src/vfunc-call.ts +3 -16
package/src/register-class.ts
CHANGED
|
@@ -19,6 +19,11 @@ import {
|
|
|
19
19
|
SET_PROPERTY_VFUNC,
|
|
20
20
|
toNativeProperties,
|
|
21
21
|
} from "./properties.js";
|
|
22
|
+
import {
|
|
23
|
+
descriptorFreePropertySpec,
|
|
24
|
+
propertyMapOverride,
|
|
25
|
+
writablePropertyMapOverride,
|
|
26
|
+
} from "./property-brand.js";
|
|
22
27
|
import {
|
|
23
28
|
getClassStructClass,
|
|
24
29
|
getClassType,
|
|
@@ -30,13 +35,19 @@ import {
|
|
|
30
35
|
wrapHandle,
|
|
31
36
|
} from "./registry.js";
|
|
32
37
|
import {
|
|
38
|
+
classSignalMember,
|
|
39
|
+
naturalSignalMember,
|
|
40
|
+
signalEmitMapOverride,
|
|
41
|
+
signalMapOverride,
|
|
42
|
+
} from "./signal-brand.js";
|
|
43
|
+
import {
|
|
44
|
+
canonicalSignalName,
|
|
33
45
|
connectClosureSignal,
|
|
34
46
|
type DeclaredSignalTypes,
|
|
35
47
|
emitDeclaredSignal,
|
|
36
|
-
|
|
48
|
+
installSignalDispatch,
|
|
37
49
|
overrideSignalClassClosure,
|
|
38
50
|
signalForHandlerName,
|
|
39
|
-
type SignalHandler,
|
|
40
51
|
signalIdFor,
|
|
41
52
|
} from "./signal.js";
|
|
42
53
|
import {
|
|
@@ -52,105 +63,284 @@ import {
|
|
|
52
63
|
} from "./type.js";
|
|
53
64
|
import { findClassVfuncDescriptor, findInterfaceVfuncDescriptor } from "./vfunc.js";
|
|
54
65
|
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
-
* `__impl__` exists only in the type system: it carries the interface's `Impl` type, of which a class
|
|
58
|
-
* has to match every member it declares itself, which rejects a class value and a member whose
|
|
59
|
-
* signature does not fit the slot it fills. Leaving a slot to the interface is not rejected,
|
|
60
|
-
* because `registerClass` does not reject it either: every member of an `Impl` type is optional,
|
|
61
|
-
* and the `Partial` holds that open whatever the type declares. The `object` beside it keeps
|
|
62
|
-
* TypeScript from also demanding one member in common. An interface that introspection describes
|
|
63
|
-
* no vtable for carries `unknown`, since it has no slot a class could fill.
|
|
64
|
-
*/
|
|
65
|
-
type Interface<TImpl> = AnyClass & {
|
|
66
|
+
/** A generated interface value, such as `Gio.ListModel`, accepted by {@link registerClass}. */
|
|
67
|
+
type Interface<TImpl, TInstance = object> = AnyClass & {
|
|
66
68
|
/** Type-level slot holding the interface's `Impl` type; no value ever carries it. */
|
|
67
|
-
__impl__: (impl: Partial<TImpl> & object) =>
|
|
69
|
+
__impl__: (impl: Partial<TImpl> & object) => TInstance;
|
|
68
70
|
};
|
|
69
71
|
|
|
70
|
-
/**
|
|
71
|
-
* One key of `RegisterClassOptions.properties` with every underscore turned into the dash a canonical
|
|
72
|
-
* GObject property name separates its words with.
|
|
73
|
-
*/
|
|
72
|
+
/** Converts underscores in a property name to canonical dashes. */
|
|
74
73
|
type Dashed<TName extends string> = TName extends `${infer THead}_${infer TTail}`
|
|
75
74
|
? Dashed<`${THead}-${TTail}`>
|
|
76
75
|
: TName;
|
|
77
76
|
|
|
78
|
-
/**
|
|
79
|
-
* One dashed key in the camelCase spelling the accessors {@link registerClass} installs carry, which is
|
|
80
|
-
* the spelling the hooks that address a property by name take.
|
|
81
|
-
*/
|
|
77
|
+
/** Converts a dashed property name to its JavaScript spelling. */
|
|
82
78
|
type Camelized<TName extends string> = TName extends `${infer THead}-${infer TTail}`
|
|
83
79
|
? `${THead}${Capitalize<Camelized<TTail>>}`
|
|
84
80
|
: TName;
|
|
85
81
|
|
|
86
|
-
/**
|
|
87
|
-
* The names a registered class carries in its property map: every key of
|
|
88
|
-
* `RegisterClassOptions.properties` in camelCase, whichever spelling it was written in.
|
|
89
|
-
* A `properties` object given a type of its own rather than left to inference has `string` for its key
|
|
90
|
-
* type and names nothing, because a name only known as `string` addresses no member in particular.
|
|
91
|
-
*/
|
|
82
|
+
/** Property-map keys in the camelCase spelling hooks use. */
|
|
92
83
|
type InstalledNames<TProperties> = string extends keyof TProperties
|
|
93
84
|
? never
|
|
94
85
|
: Camelized<Dashed<keyof TProperties & string>>;
|
|
95
86
|
|
|
96
|
-
/**
|
|
97
|
-
* The base names the signal surface takes for the signals `RegisterClassOptions.signals` declares:
|
|
98
|
-
* each name as written, plus its canonical spelling with underscores turned into dashes, which
|
|
99
|
-
* GObject knows the signal by too.
|
|
100
|
-
*/
|
|
87
|
+
/** Declared signal names in their original and canonical spellings. */
|
|
101
88
|
type DeclaredSignalBase<TSignals> = (keyof TSignals & string) | Dashed<keyof TSignals & string>;
|
|
102
|
-
/**
|
|
103
|
-
* The names `connect` and `emit` take for one of the signals `RegisterClassOptions.signals`
|
|
104
|
-
* declares: each spelling of each name, plus its detailed form for a signal emitted with a
|
|
105
|
-
* `::detail` suffix.
|
|
106
|
-
*/
|
|
89
|
+
/** Declared signal names, including detailed forms. */
|
|
107
90
|
type DeclaredSignalName<TSignals> = DeclaredSignalBase<TSignals> | `${DeclaredSignalBase<TSignals>}::${string}`;
|
|
108
91
|
|
|
109
|
-
/**
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
92
|
+
/** Signal methods added for declared names. */
|
|
93
|
+
type DeclaredSignalMethods<TSignals, TBlockedMembers extends PropertyKey> = {
|
|
94
|
+
/** Type-level map used by signal hooks. */
|
|
95
|
+
__signals__?: Record<DeclaredSignalName<TSignals>, (...args: never[]) => unknown>;
|
|
96
|
+
} &
|
|
97
|
+
Pick<
|
|
98
|
+
{
|
|
99
|
+
connect(
|
|
100
|
+
signal: DeclaredSignalName<TSignals>,
|
|
101
|
+
handler: (...args: never[]) => unknown,
|
|
102
|
+
isAfter?: boolean,
|
|
103
|
+
): number;
|
|
104
|
+
emit(sigName: DeclaredSignalName<TSignals>, ...args: unknown[]): unknown;
|
|
105
|
+
on(sigName: DeclaredSignalName<TSignals>, callback: (...args: never[]) => unknown, isAfter?: boolean): unknown;
|
|
106
|
+
once(
|
|
107
|
+
sigName: DeclaredSignalName<TSignals>,
|
|
108
|
+
callback: (...args: never[]) => unknown,
|
|
109
|
+
isAfter?: boolean,
|
|
110
|
+
): unknown;
|
|
111
|
+
off(sigName: DeclaredSignalName<TSignals>, callback: (...args: never[]) => unknown): unknown;
|
|
112
|
+
},
|
|
113
|
+
Exclude<"connect" | "emit" | "off" | "on" | "once", TBlockedMembers>
|
|
114
|
+
>;
|
|
115
|
+
|
|
116
|
+
/** A registered instance with declared signal methods and property metadata. */
|
|
117
|
+
type RegisteredInstance<
|
|
118
|
+
TInstance,
|
|
119
|
+
TProperties,
|
|
120
|
+
TSignals,
|
|
121
|
+
TInterfaces extends readonly Interface<TInstance>[],
|
|
122
|
+
TRemainingInterfaces extends readonly Interface<TInstance>[] = TInterfaces,
|
|
123
|
+
TMemberSurface = object,
|
|
124
|
+
TSignalSurface = TInstance extends { [signalMapOverride]?: infer TResolver }
|
|
125
|
+
? TResolver extends () => infer TMap
|
|
126
|
+
? NonNullable<TMap>
|
|
127
|
+
: TInstance extends { __signals__?: infer TMap }
|
|
128
|
+
? NonNullable<TMap>
|
|
129
|
+
: object
|
|
130
|
+
: TInstance extends { __signals__?: infer TMap }
|
|
131
|
+
? NonNullable<TMap>
|
|
132
|
+
: object,
|
|
133
|
+
TSignalEmitSurface = TInstance extends { [signalEmitMapOverride]?: infer TResolver }
|
|
134
|
+
? TResolver extends () => infer TMap
|
|
135
|
+
? NonNullable<TMap>
|
|
136
|
+
: TInstance extends { __signalEmit__?: infer TMap }
|
|
137
|
+
? NonNullable<TMap>
|
|
138
|
+
: object
|
|
139
|
+
: TInstance extends { __signalEmit__?: infer TMap }
|
|
140
|
+
? NonNullable<TMap>
|
|
141
|
+
: object,
|
|
142
|
+
TPropertySurface = TInstance extends { [propertyMapOverride]?: infer TResolver }
|
|
143
|
+
? TResolver extends () => infer TMap
|
|
144
|
+
? NonNullable<TMap>
|
|
145
|
+
: TInstance extends { __properties__?: infer TMap }
|
|
146
|
+
? NonNullable<TMap>
|
|
147
|
+
: object
|
|
148
|
+
: TInstance extends { __properties__?: infer TMap }
|
|
149
|
+
? NonNullable<TMap>
|
|
150
|
+
: object,
|
|
151
|
+
TWritablePropertySurface = TInstance extends { [writablePropertyMapOverride]?: infer TResolver }
|
|
152
|
+
? TResolver extends () => infer TMap
|
|
153
|
+
? NonNullable<TMap>
|
|
154
|
+
: TInstance extends { __writableProperties__?: infer TMap }
|
|
155
|
+
? NonNullable<TMap>
|
|
156
|
+
: object
|
|
157
|
+
: TInstance extends { __writableProperties__?: infer TMap }
|
|
158
|
+
? NonNullable<TMap>
|
|
159
|
+
: object,
|
|
160
|
+
TNaturalInstanceMembers extends PropertyKey = TInstance extends {
|
|
161
|
+
[naturalSignalMember]?: infer TMembers;
|
|
162
|
+
}
|
|
163
|
+
? keyof NonNullable<TMembers>
|
|
164
|
+
: never,
|
|
165
|
+
TClassInstanceSignals extends PropertyKey = TInstance extends {
|
|
166
|
+
[classSignalMember]?: infer TMembers;
|
|
167
|
+
}
|
|
168
|
+
? keyof NonNullable<TMembers>
|
|
169
|
+
: never,
|
|
170
|
+
TLegacySignalMembers extends PropertyKey = "connect" | "disconnect" | "emit" | "off" | "on" | "once",
|
|
171
|
+
TInstalledPropertyCandidate = TInstance & TMemberSurface,
|
|
172
|
+
TRegisteredPropertySurface = Omit<TPropertySurface, InstalledNames<TProperties>> &
|
|
173
|
+
Pick<
|
|
174
|
+
TInstalledPropertyCandidate,
|
|
175
|
+
(string extends keyof TProperties
|
|
176
|
+
? never
|
|
177
|
+
: {
|
|
178
|
+
[K in keyof TProperties & string]: TProperties[K] extends {
|
|
179
|
+
readonly [descriptorFreePropertySpec]: true;
|
|
180
|
+
}
|
|
181
|
+
? Camelized<Dashed<K>>
|
|
182
|
+
: never;
|
|
183
|
+
}[keyof TProperties & string]) & {
|
|
184
|
+
[K in keyof TInstalledPropertyCandidate]-?: Extract<
|
|
185
|
+
TInstalledPropertyCandidate[K],
|
|
186
|
+
(...args: never[]) => unknown
|
|
187
|
+
> extends never
|
|
188
|
+
? K
|
|
189
|
+
: never;
|
|
190
|
+
}[keyof TInstalledPropertyCandidate]
|
|
191
|
+
>,
|
|
192
|
+
TRegisteredWritablePropertySurface = Omit<TWritablePropertySurface, InstalledNames<TProperties>> &
|
|
193
|
+
Pick<
|
|
194
|
+
TInstalledPropertyCandidate,
|
|
195
|
+
(string extends keyof TProperties
|
|
196
|
+
? never
|
|
197
|
+
: {
|
|
198
|
+
[K in keyof TProperties & string]: TProperties[K] extends {
|
|
199
|
+
readonly [descriptorFreePropertySpec]: true;
|
|
200
|
+
}
|
|
201
|
+
? Camelized<Dashed<K>>
|
|
202
|
+
: never;
|
|
203
|
+
}[keyof TProperties & string]) & {
|
|
204
|
+
[K in keyof TInstalledPropertyCandidate]-?: Extract<
|
|
205
|
+
TInstalledPropertyCandidate[K],
|
|
206
|
+
(...args: never[]) => unknown
|
|
207
|
+
> extends never
|
|
208
|
+
? (<U>(probe: U) => U extends { [P in K]: TInstalledPropertyCandidate[P] } ? 1 : 2) extends
|
|
209
|
+
(<U>(probe: U) =>
|
|
210
|
+
U extends { -readonly [P in K]: TInstalledPropertyCandidate[P] } ? 1 : 2)
|
|
211
|
+
? K
|
|
212
|
+
: never
|
|
213
|
+
: never;
|
|
214
|
+
}[keyof TInstalledPropertyCandidate]
|
|
215
|
+
>,
|
|
216
|
+
> = TRemainingInterfaces extends readonly [
|
|
217
|
+
infer TInterface extends Interface<TInstance>,
|
|
218
|
+
...infer TRest extends readonly Interface<TInstance>[],
|
|
219
|
+
]
|
|
220
|
+
? (ReturnType<TInterface["__impl__"]> extends infer TInterfaceInstance extends object
|
|
221
|
+
? RegisteredInstance<
|
|
222
|
+
TInstance,
|
|
223
|
+
TProperties,
|
|
224
|
+
TSignals,
|
|
225
|
+
TInterfaces,
|
|
226
|
+
TRest,
|
|
227
|
+
TMemberSurface &
|
|
228
|
+
Omit<
|
|
229
|
+
TInterfaceInstance,
|
|
230
|
+
| keyof TInstance |
|
|
231
|
+
keyof TMemberSurface |
|
|
232
|
+
"__properties__" |
|
|
233
|
+
"__writableProperties__" |
|
|
234
|
+
"__signalEmit__" |
|
|
235
|
+
"__signals__" |
|
|
236
|
+
TLegacySignalMembers
|
|
237
|
+
> & {
|
|
238
|
+
[K in Extract<
|
|
239
|
+
TInterfaceInstance extends { [naturalSignalMember]?: infer TMembers }
|
|
240
|
+
? keyof NonNullable<TMembers>
|
|
241
|
+
: never,
|
|
242
|
+
TLegacySignalMembers
|
|
243
|
+
> as K extends TNaturalInstanceMembers | keyof TMemberSurface
|
|
244
|
+
? never
|
|
245
|
+
: K]: K extends keyof TInterfaceInstance ? TInterfaceInstance[K] : never;
|
|
246
|
+
},
|
|
247
|
+
TInterfaceInstance extends { __signals__?: infer TNextSignalMap } ? Omit<
|
|
248
|
+
TSignalSurface,
|
|
249
|
+
keyof {
|
|
250
|
+
[K in keyof NonNullable<TNextSignalMap> as K extends string
|
|
251
|
+
? Dashed<
|
|
252
|
+
K extends `${infer TBase}::${string}` ? TBase : K
|
|
253
|
+
> extends TClassInstanceSignals | Dashed<keyof TSignals & string>
|
|
254
|
+
? never
|
|
255
|
+
: K
|
|
256
|
+
: K]: NonNullable<TNextSignalMap>[K];
|
|
257
|
+
}
|
|
258
|
+
> & {
|
|
259
|
+
[K in keyof NonNullable<TNextSignalMap> as K extends string
|
|
260
|
+
? Dashed<
|
|
261
|
+
K extends `${infer TBase}::${string}` ? TBase : K
|
|
262
|
+
> extends TClassInstanceSignals | Dashed<keyof TSignals & string>
|
|
263
|
+
? never
|
|
264
|
+
: K
|
|
265
|
+
: K]: NonNullable<TNextSignalMap>[K];
|
|
266
|
+
}
|
|
267
|
+
: TSignalSurface,
|
|
268
|
+
TInterfaceInstance extends { __signalEmit__?: infer TNextSignalEmitMap } ? Omit<
|
|
269
|
+
TSignalEmitSurface,
|
|
270
|
+
keyof {
|
|
271
|
+
[K in keyof NonNullable<TNextSignalEmitMap> as K extends string
|
|
272
|
+
? Dashed<
|
|
273
|
+
K extends `${infer TBase}::${string}` ? TBase : K
|
|
274
|
+
> extends TClassInstanceSignals | Dashed<keyof TSignals & string>
|
|
275
|
+
? never
|
|
276
|
+
: K
|
|
277
|
+
: K]: NonNullable<TNextSignalEmitMap>[K];
|
|
278
|
+
}
|
|
279
|
+
> & {
|
|
280
|
+
[K in keyof NonNullable<TNextSignalEmitMap> as K extends string
|
|
281
|
+
? Dashed<
|
|
282
|
+
K extends `${infer TBase}::${string}` ? TBase : K
|
|
283
|
+
> extends TClassInstanceSignals | Dashed<keyof TSignals & string>
|
|
284
|
+
? never
|
|
285
|
+
: K
|
|
286
|
+
: K]: NonNullable<TNextSignalEmitMap>[K];
|
|
287
|
+
}
|
|
288
|
+
: TSignalEmitSurface,
|
|
289
|
+
TPropertySurface &
|
|
290
|
+
Omit<
|
|
291
|
+
TInterfaceInstance extends { [propertyMapOverride]?: infer TResolver }
|
|
292
|
+
? TResolver extends () => infer TMap
|
|
293
|
+
? NonNullable<TMap>
|
|
294
|
+
: TInterfaceInstance extends { __properties__?: infer TMap }
|
|
295
|
+
? NonNullable<TMap>
|
|
296
|
+
: object
|
|
297
|
+
: TInterfaceInstance extends { __properties__?: infer TMap }
|
|
298
|
+
? NonNullable<TMap>
|
|
299
|
+
: object,
|
|
300
|
+
keyof TPropertySurface
|
|
301
|
+
>,
|
|
302
|
+
TWritablePropertySurface &
|
|
303
|
+
Omit<
|
|
304
|
+
TInterfaceInstance extends { [writablePropertyMapOverride]?: infer TResolver }
|
|
305
|
+
? TResolver extends () => infer TMap
|
|
306
|
+
? NonNullable<TMap>
|
|
307
|
+
: TInterfaceInstance extends { __writableProperties__?: infer TMap }
|
|
308
|
+
? NonNullable<TMap>
|
|
309
|
+
: object
|
|
310
|
+
: TInterfaceInstance extends { __writableProperties__?: infer TMap }
|
|
311
|
+
? NonNullable<TMap>
|
|
312
|
+
: object,
|
|
313
|
+
keyof TWritablePropertySurface
|
|
314
|
+
>,
|
|
315
|
+
TNaturalInstanceMembers,
|
|
316
|
+
TClassInstanceSignals,
|
|
317
|
+
TLegacySignalMembers
|
|
318
|
+
>
|
|
319
|
+
: never) : TInstance &
|
|
320
|
+
TMemberSurface &
|
|
321
|
+
DeclaredSignalMethods<
|
|
322
|
+
TSignals,
|
|
323
|
+
TNaturalInstanceMembers | Extract<keyof TMemberSurface, TLegacySignalMembers>
|
|
324
|
+
> & {
|
|
325
|
+
[naturalSignalMember]?: Record<
|
|
326
|
+
TNaturalInstanceMembers | Extract<keyof TMemberSurface, TLegacySignalMembers>,
|
|
327
|
+
true
|
|
328
|
+
>;
|
|
329
|
+
[classSignalMember]?: Record<
|
|
330
|
+
TClassInstanceSignals | Dashed<keyof TSignals & string>,
|
|
331
|
+
true
|
|
332
|
+
>;
|
|
333
|
+
[signalMapOverride]?: () => Omit<TSignalSurface, DeclaredSignalName<TSignals>> &
|
|
334
|
+
Record<DeclaredSignalName<TSignals>, (...args: never[]) => unknown>;
|
|
335
|
+
[signalEmitMapOverride]?: () => Omit<TSignalEmitSurface, DeclaredSignalName<TSignals>> &
|
|
336
|
+
Record<DeclaredSignalName<TSignals>, { args: unknown[]; result: unknown }>;
|
|
337
|
+
[propertyMapOverride]?: () => TRegisteredPropertySurface;
|
|
338
|
+
[writablePropertyMapOverride]?: () => TRegisteredWritablePropertySurface;
|
|
339
|
+
__properties__: TRegisteredPropertySurface;
|
|
340
|
+
__writableProperties__: TRegisteredWritablePropertySurface;
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
/** A registered class's construct signature and prototype. */
|
|
154
344
|
type RegisteredConstructor<TClass, TArgs extends unknown[], TInstance> = {
|
|
155
345
|
/** Object the class's instances inherit from. */
|
|
156
346
|
prototype: TInstance;
|
|
@@ -162,45 +352,29 @@ type RegisteredConstructor<TClass, TArgs extends unknown[], TInstance> = {
|
|
|
162
352
|
type RegisteredParts<TClass, TArgs extends unknown[], TInstance> = Omit<TClass, "prototype"> &
|
|
163
353
|
RegisteredConstructor<TClass, TArgs, TInstance>;
|
|
164
354
|
|
|
165
|
-
/**
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
355
|
+
/** The registered class with its declared properties and signals. */
|
|
356
|
+
type RegisteredClass<
|
|
357
|
+
TClass extends AnyClass,
|
|
358
|
+
TProperties,
|
|
359
|
+
TSignals,
|
|
360
|
+
TInterfaces extends readonly Interface<TClass["prototype"]>[],
|
|
361
|
+
> =
|
|
172
362
|
TClass extends abstract new (...args: infer TArgs) => infer TInstance
|
|
173
|
-
? RegisteredParts<TClass, TArgs, RegisteredInstance<TInstance, TProperties, TSignals>>
|
|
363
|
+
? RegisteredParts<TClass, TArgs, RegisteredInstance<TInstance, TProperties, TSignals, TInterfaces>>
|
|
174
364
|
: never;
|
|
175
365
|
|
|
176
|
-
/**
|
|
177
|
-
* A GType in the form `RegisterClassOptions.signals` takes one: the numeric GType itself, such as
|
|
178
|
-
* `TYPE_STRING` from `@gtkx/gi/gobject`, or a class carrying one, which is any generated wrapper
|
|
179
|
-
* class and any class an earlier {@link registerClass} call registered.
|
|
180
|
-
*/
|
|
366
|
+
/** A numeric GType or a generated or registered wrapper class. */
|
|
181
367
|
type SignalGType = bigint | AnyClass<TypedClass>;
|
|
182
368
|
|
|
183
|
-
/**
|
|
184
|
-
* One signal `RegisterClassOptions.signals` creates on the new type, sitting under the signal's
|
|
185
|
-
* name. Every part is optional: `{}` declares a signal with no arguments and no return value that
|
|
186
|
-
* runs its handlers in the default `RUN_FIRST` stage.
|
|
187
|
-
*/
|
|
369
|
+
/** A signal installed by {@link registerClass}. */
|
|
188
370
|
type SignalSpec = {
|
|
189
|
-
/**
|
|
190
|
-
* `GObject.SignalFlags` bit mask for the signal, defaulting to `RUN_FIRST`. `DETAILED` lets
|
|
191
|
-
* handlers connect to and emissions name a `::detail` suffix.
|
|
192
|
-
*/
|
|
371
|
+
/** `GObject.SignalFlags` bit mask, defaulting to `RUN_FIRST`. */
|
|
193
372
|
flags?: number;
|
|
194
|
-
/**
|
|
373
|
+
/** Argument GTypes, defaulting to none. */
|
|
195
374
|
paramTypes?: SignalGType[];
|
|
196
|
-
/** GType
|
|
375
|
+
/** Return GType, defaulting to none. */
|
|
197
376
|
returnType?: SignalGType;
|
|
198
|
-
/**
|
|
199
|
-
* How the emission combines what its handlers return, limited to the accumulators GObject
|
|
200
|
-
* ships: `"first-wins"` stops the emission at the first handler and keeps its result, and
|
|
201
|
-
* `"true-handled"` runs handlers until one returns `true`, which requires a boolean
|
|
202
|
-
* `returnType`. Without one, every handler runs and the last result stands.
|
|
203
|
-
*/
|
|
377
|
+
/** Combines handler results; omitted means the last result wins. */
|
|
204
378
|
accumulator?: "first-wins" | "true-handled";
|
|
205
379
|
};
|
|
206
380
|
|
|
@@ -209,136 +383,42 @@ type RegisterClassOptions<
|
|
|
209
383
|
TInstance extends object,
|
|
210
384
|
TProperties extends Record<string, PropertySpec>,
|
|
211
385
|
TSignals extends Record<string, SignalSpec>,
|
|
386
|
+
TInterfaces extends readonly Interface<TInstance>[],
|
|
212
387
|
> = {
|
|
213
|
-
/**
|
|
214
|
-
* Name to register the new GType under, defaulting to the class's own name. Either way the
|
|
215
|
-
* name has to be a valid GType name: at least three characters, starting with a letter or
|
|
216
|
-
* underscore, the rest letters, digits, `-`, `_` or `+`. Any other name throws a `TypeError`.
|
|
217
|
-
*/
|
|
388
|
+
/** Registered GType name, defaulting to the class name. */
|
|
218
389
|
typeName?: string;
|
|
219
|
-
/**
|
|
220
|
-
* Registers the new GType abstract, the way `G_TYPE_FLAG_ABSTRACT` marks a C type: the class
|
|
221
|
-
* still serves as a parent for further registered subclasses, which instantiate as usual, but
|
|
222
|
-
* constructing it directly throws, whether from JavaScript or from a native caller.
|
|
223
|
-
*/
|
|
390
|
+
/** Prevents direct construction while allowing registered subclasses. */
|
|
224
391
|
abstract?: boolean;
|
|
225
|
-
/**
|
|
226
|
-
* Name instances of the new type carry in CSS, applied through `gtk_widget_class_set_css_name`
|
|
227
|
-
* from inside the type's `class_init`, so every instance is born with it, wherever it is
|
|
228
|
-
* created from. Requires the class to extend `Gtk.Widget`; registering a non-widget with a
|
|
229
|
-
* `cssName` throws.
|
|
230
|
-
*/
|
|
392
|
+
/** CSS node name for a `Gtk.Widget` subclass. */
|
|
231
393
|
cssName?: string;
|
|
232
394
|
/**
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
* new type's class struct wrapped in its generated GTypeStruct wrapper, so class-level setup
|
|
236
|
-
* calls such as `Gtk.WidgetClass.installAction`, `Gtk.WidgetClass.addShortcut` and
|
|
237
|
-
* `Gtk.WidgetClass.setLayoutManagerType` have somewhere to land. The wrapper serves the
|
|
238
|
-
* members of every struct in the parent chain on one object: a widget subclass sees
|
|
239
|
-
* `Gtk.WidgetClass` and `GObject.ObjectClass` members alike, so the parameter can be declared
|
|
240
|
-
* as whichever of those types the hook needs. The class struct belongs to the type system for
|
|
241
|
-
* the life of the process, so keeping the wrapper around past the hook is safe, if rarely
|
|
242
|
-
* useful. An exception the hook throws propagates out of `registerClass`, with the type
|
|
243
|
-
* already registered: GObject offers no way to unregister a static type.
|
|
395
|
+
* Runs once after registration with the wrapped class struct. An exception propagates after
|
|
396
|
+
* the static GType has already been registered and cannot be undone.
|
|
244
397
|
*/
|
|
245
398
|
classInit?(typeStruct: object): void;
|
|
399
|
+
/** Interfaces implemented through matching `vfunc` methods. */
|
|
400
|
+
implements?: TInterfaces;
|
|
246
401
|
/**
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*/
|
|
252
|
-
implements?: Interface<TInstance>[];
|
|
253
|
-
/**
|
|
254
|
-
* Properties to install on the new type, keyed by the name JavaScript addresses each one by and
|
|
255
|
-
* valued with the `GObject.ParamSpec` describing it. A key is read in camelCase however it is
|
|
256
|
-
* written, so `dewPoint`, `dew_point` and `dew-point` all name the same member, and the ParamSpec
|
|
257
|
-
* has to carry a name that reads back as that same member, such as `dew-point`, or registration
|
|
258
|
-
* throws: the ParamSpec's name is the one GObject emits `notify` with, and a name the key does
|
|
259
|
-
* not spell reaches nothing that listens for it. A word starting with a digit is a word of its
|
|
260
|
-
* own on either side of that reading, so `level2Depth` takes a ParamSpec named `level-2-depth`
|
|
261
|
-
* as readily as one named `level2-depth`, the way `WebKit.Settings` names
|
|
262
|
-
* `enable-2d-canvas-acceleration` for its `enable2dCanvasAcceleration` member. An uppercase
|
|
263
|
-
* letter in the ParamSpec's own name is refused, since GObject notifies under that spelling
|
|
264
|
-
* and nothing else reads it back. Every property gains prototype accessors, one for the key as
|
|
265
|
-
* written, one for it with dashes turned into underscores and one for it in camelCase, each
|
|
266
|
-
* unless the class already defines that name. They serve the value from storage of their own on
|
|
267
|
-
* the instance, which is also what the type's `get_property` and `set_property` slots read and
|
|
268
|
-
* write, so a value set from JavaScript, from `g_object_set_property` and at construction all
|
|
269
|
-
* land in the same place.
|
|
270
|
-
*
|
|
271
|
-
* A write the ParamSpec would refuse throws rather than reaching GObject, which reports such a
|
|
272
|
-
* write as a GLib critical and drops it: a `TypeError` for a read-only or construct-only
|
|
273
|
-
* property and for a value of a type the property cannot hold, and a `RangeError` for a value
|
|
274
|
-
* the ParamSpec rejects. The same checks run over a value handed to the constructor, where
|
|
275
|
-
* a construct-only property is the one that is writable. An accepted write emits one `notify`,
|
|
276
|
-
* which a `freeze_notify` batch collects; a write of the value the property already holds is
|
|
277
|
-
* dropped and emits none.
|
|
278
|
-
*
|
|
279
|
-
* `null` and `undefined` both mean NULL, and mean it only where the ParamSpec's own type holds
|
|
280
|
-
* NULL, which is a string, string-array, boxed, object, interface, param, variant or pointer
|
|
281
|
-
* property. Such a property holds the `null` either spelling wrote, so the member, the type's
|
|
282
|
-
* `get_property` slot and `g_object_get_property` serve the same thing, and writing the other
|
|
283
|
-
* spelling over it emits no `notify`. Every other property, so every integer, floating-point,
|
|
284
|
-
* boolean, enum, flags and GType one, refuses both with the same `TypeError` it refuses a
|
|
285
|
-
* string with, and keeps the value it already holds. It refuses them for what it holds rather
|
|
286
|
-
* than for its range, whatever that range is: the type is checked before the range, so a
|
|
287
|
-
* `gint` whose range excludes 0 answers a nullish with that same `TypeError` and never with
|
|
288
|
-
* the `RangeError` that names the value GObject would put in its place. The one place
|
|
289
|
-
* `undefined` means something else is the constructor, which reads it as the property not
|
|
290
|
-
* being given at all and leaves it at the ParamSpec's default, so a property is never handed a
|
|
291
|
-
* value it cannot serve back.
|
|
292
|
-
*
|
|
293
|
-
* A floating-point property takes every JavaScript number, `NaN` and both infinities
|
|
294
|
-
* included, and its ParamSpec alone rules on which of them the range admits: a `gdouble`
|
|
295
|
-
* bounded by `-Infinity` and `Infinity` holds either infinity, and a magnitude a bounded
|
|
296
|
-
* one excludes, like any `NaN`, comes back as the `RangeError` that names what GObject
|
|
297
|
-
* would put in its place rather than as the `TypeError` a type the property cannot hold
|
|
298
|
-
* earns. A `gfloat` property holds what GObject narrows the double to, so it serves `0.1`
|
|
299
|
-
* back as `0.10000000149011612` and a finite magnitude no `gfloat` reaches as an infinity,
|
|
300
|
-
* which the range then rules on in turn. That narrowing belongs to the property alone: the
|
|
301
|
-
* same magnitude written to a `gfloat` through a generated binding, a signal argument or a
|
|
302
|
-
* closure return is refused outright rather than narrowed.
|
|
303
|
-
*
|
|
304
|
-
* A generated property of a wrapped type answers a nullish differently, and the two halves of
|
|
305
|
-
* the API disagree here: that property marshals what it is written through its descriptor
|
|
306
|
-
* rather than through the checks above, so `new Gtk.Label({ widthRequest: null })` and a later
|
|
307
|
-
* write of `null` to that member both land 0, where a `gint` installed here refuses both.
|
|
308
|
-
*
|
|
309
|
-
* A class that defines the camelCase member itself owns the property: its own accessor decides
|
|
310
|
-
* what a write means, the other spellings forward to it, and the type's property slots read
|
|
311
|
-
* and write it rather than the generated storage.
|
|
402
|
+
* ParamSpecs keyed by their JavaScript property names. Keys and ParamSpec names must canonicalize
|
|
403
|
+
* to the same member. Writes validate flags, types, and ranges and notify only on changes.
|
|
404
|
+
* Nullish values require a nullable GType; constructor `undefined` means omitted. An existing
|
|
405
|
+
* camelCase accessor remains authoritative.
|
|
312
406
|
*/
|
|
313
407
|
properties?: TProperties;
|
|
314
408
|
/**
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
* in lowercase letters, digits, `-` and `_`, and be new to the type: one an ancestor type or a
|
|
318
|
-
* listed interface already carries throws, and so does one carrying an uppercase letter, which
|
|
319
|
-
* GObject would carry under that exact spelling, out of reach of both its dashed spelling and
|
|
320
|
-
* its `on<SignalName>` default handler. Either word separator spells the same signal, so a
|
|
321
|
-
* signal declared as `data_changed` is connected to and emitted as `data-changed` too.
|
|
322
|
-
*
|
|
323
|
-
* Instances connect and emit by name through the same `connect`, `on`, `once`, `off` and
|
|
324
|
-
* `emit` surface inherited signals use: `registerClass` wraps `connect` and `emit` on the
|
|
325
|
-
* class's prototype to serve the declared names, unless the class defines the member itself,
|
|
326
|
-
* and hands every other name to the inherited implementation. A handler receives the
|
|
327
|
-
* emission's arguments without the leading emitter, matching a generated signal, and what it
|
|
328
|
-
* returns becomes the emission's return value when the signal declares one.
|
|
329
|
-
*
|
|
330
|
-
* The declared parameter GTypes rule the emission: `emit` takes exactly one argument per
|
|
331
|
-
* declared parameter, throwing a `TypeError` for any other count, and converts each argument
|
|
332
|
-
* into a `GValue` of the declared type, throwing for a value that type cannot hold. The signals
|
|
333
|
-
* are created with no class closure of their own, but a method named `on<SignalName>`
|
|
334
|
-
* becomes the signal's default handler, the way every `on`-prefixed method that names a
|
|
335
|
-
* signal the type carries does; see {@link registerClass}.
|
|
409
|
+
* New canonical signal names and specs. Declared GTypes validate emissions, and a matching
|
|
410
|
+
* `on<SignalName>` method becomes the default handler.
|
|
336
411
|
*/
|
|
337
412
|
signals?: TSignals;
|
|
338
413
|
};
|
|
339
414
|
|
|
340
415
|
/** {@link RegisterClassOptions} with the widest instance and property types {@link registerClass} accepts. */
|
|
341
|
-
type AnyRegisterClassOptions = RegisterClassOptions<
|
|
416
|
+
type AnyRegisterClassOptions = RegisterClassOptions<
|
|
417
|
+
object,
|
|
418
|
+
Record<string, PropertySpec>,
|
|
419
|
+
Record<string, SignalSpec>,
|
|
420
|
+
Interface<object>[]
|
|
421
|
+
>;
|
|
342
422
|
type VfuncFn = NativeRegisterClassVfunc["fn"];
|
|
343
423
|
type DiscoveredVfunc = VfuncDescriptor & { methodName: string; fn: VfuncFn };
|
|
344
424
|
type MethodTable = Map<string, VfuncFn>;
|
|
@@ -365,11 +445,6 @@ type PropertyVfuncSpec = {
|
|
|
365
445
|
type ArgPatch = { isCallerAllocated: true } | { isCallScoped: true };
|
|
366
446
|
type DeclaredSignals = { native: NativeRegisterClassSignal[]; table: Map<string, DeclaredSignalTypes> };
|
|
367
447
|
|
|
368
|
-
type SignalMethodHost = {
|
|
369
|
-
connect?: (signal: string, handler: SignalHandler, isAfter?: boolean) => number;
|
|
370
|
-
emit?: (sigName: string, ...args: unknown[]) => unknown;
|
|
371
|
-
};
|
|
372
|
-
|
|
373
448
|
const INSTANCE_ARG_INDEX = 0;
|
|
374
449
|
const VALUE_ARG_INDEX = 2;
|
|
375
450
|
const TEARDOWN_VFUNC_NAMES: Set<string> = new Set(["dispose", "finalize"]);
|
|
@@ -388,66 +463,29 @@ const UPPER_CASE_PATTERN = /[A-Z]/;
|
|
|
388
463
|
const SIGNAL_OVERRIDE_PATTERN = /^on[A-Z]/;
|
|
389
464
|
|
|
390
465
|
/**
|
|
391
|
-
* Registers a
|
|
392
|
-
*
|
|
393
|
-
* `
|
|
466
|
+
* Registers a wrapper subclass as a GType with discovered vfuncs, properties, signals, and interfaces.
|
|
467
|
+
* Vfuncs must be prototype methods; function-valued fields never reach the vtable. A matching
|
|
468
|
+
* `on<SignalName>` method becomes the signal's default handler.
|
|
394
469
|
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
* `
|
|
398
|
-
* listed interface has a prerequisite that neither the parent type nor another listed interface meets,
|
|
399
|
-
* when the list names `Gio.AsyncInitable` as an interface the parent type does not already
|
|
400
|
-
* implement and no method on the chain fills `vfuncInitAsync`, since the default `init_async`
|
|
401
|
-
* would run `vfuncInit` on a worker thread, when an entry in
|
|
402
|
-
* `RegisterClassOptions.properties` names its `GObject.ParamSpec` something the key it sits under
|
|
403
|
-
* does not spell, when an entry in `RegisterClassOptions.signals` carries an invalid name, a name
|
|
404
|
-
* spelled with an uppercase letter rather than dashed, a name the type already knows, a GType
|
|
405
|
-
* that cannot hold a value, or an accumulator the spec does not admit, and when
|
|
406
|
-
* `RegisterClassOptions.cssName` is
|
|
407
|
-
* given for a class that does not extend `Gtk.Widget`. An exception thrown by
|
|
408
|
-
* `RegisterClassOptions.classInit` also propagates, after the type has already been registered.
|
|
470
|
+
* `vfuncConstructed` runs before field initializers and the constructor body. Native-created
|
|
471
|
+
* instances never run the JavaScript constructor, so native-required state belongs in properties
|
|
472
|
+
* or `vfuncConstructed`. A new `Gio.AsyncInitable` must implement `vfuncInitAsync`.
|
|
409
473
|
*
|
|
410
|
-
*
|
|
411
|
-
*
|
|
412
|
-
*
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
* Declare every slot as a method: a class field holding a function, such as `vfuncGetNItems = () => 1`,
|
|
416
|
-
* is assigned to each instance after registration and never reaches the vtable.
|
|
417
|
-
*
|
|
418
|
-
* A method named `on<SignalName>` — the signal's name in camelCase after the `on`, so `onClicked`
|
|
419
|
-
* for `clicked` and `onItemsChanged` for `items-changed` — becomes that signal's default handler
|
|
420
|
-
* when the type carries the signal, whether an ancestor type or an implemented interface brings it
|
|
421
|
-
* or `RegisterClassOptions.signals` declares it. The method is installed as a class-closure
|
|
422
|
-
* override, so it runs on every emission, on the instances a native caller creates included, in
|
|
423
|
-
* the stage the signal's flags name rather than alongside connected handlers. It receives the
|
|
424
|
-
* emission's arguments without the leading emitter, with `this` bound to the emitter, and what it
|
|
425
|
-
* returns becomes the emission's result when the signal declares one. The same discovery walks the
|
|
426
|
-
* prototype chain vfunc discovery walks, and a subclass registering its own `on<SignalName>`
|
|
427
|
-
* replaces the handler for its instances, where `super.on<SignalName>()` reaches the replaced one.
|
|
428
|
-
* An `on`-prefixed method naming no signal the type carries is left alone as the ordinary method
|
|
429
|
-
* it is.
|
|
430
|
-
*
|
|
431
|
-
* An override of `vfuncConstructed` runs from inside the base constructor, before JavaScript
|
|
432
|
-
* installs the subclass's field initializers and runs its constructor body, so a field still
|
|
433
|
-
* reads `undefined` there and reading a `#private` field throws. Declare state the override
|
|
434
|
-
* touches without an initializer, and assign private state from the constructor body after
|
|
435
|
-
* `super()`. An instance a native caller creates, through `GObject.newv` or `Gtk.Builder`,
|
|
436
|
-
* never runs the subclass constructor at all, so its declared fields stay uninitialized for
|
|
437
|
-
* the object's whole life.
|
|
438
|
-
*
|
|
439
|
-
* @param klass The subclass to register.
|
|
440
|
-
* @param options What the new GType gains beyond the vtable slots the class overrides.
|
|
441
|
-
* @returns The same class, now registered, with every name in `options.properties` in its property map.
|
|
474
|
+
* @param klass The wrapper subclass to register.
|
|
475
|
+
* @param options Additional GType configuration.
|
|
476
|
+
* @returns The registered class with declared properties and signals in its type.
|
|
477
|
+
* @throws For invalid parents, names, interfaces, vfuncs, properties, signals, or widget options.
|
|
478
|
+
* A `classInit` exception propagates after the static type has been registered and cannot be undone.
|
|
442
479
|
*/
|
|
443
480
|
function registerClass<
|
|
444
481
|
T extends AnyClass,
|
|
445
482
|
TProperties extends Record<string, PropertySpec> = Record<never, PropertySpec>,
|
|
446
483
|
TSignals extends Record<string, SignalSpec> = Record<never, SignalSpec>,
|
|
484
|
+
const TInterfaces extends readonly Interface<T["prototype"]>[] = readonly Interface<T["prototype"]>[],
|
|
447
485
|
>(
|
|
448
486
|
klass: T,
|
|
449
|
-
options?: RegisterClassOptions<T["prototype"], TProperties, TSignals>,
|
|
450
|
-
): RegisteredClass<T, TProperties, TSignals>;
|
|
487
|
+
options?: RegisterClassOptions<T["prototype"], TProperties, TSignals, TInterfaces>,
|
|
488
|
+
): RegisteredClass<T, TProperties, TSignals, TInterfaces>;
|
|
451
489
|
|
|
452
490
|
function registerClass(klass: AnyClass, options: AnyRegisterClassOptions = {}): AnyClass {
|
|
453
491
|
const parentType = resolveParentType(klass);
|
|
@@ -486,7 +524,7 @@ function registerClass(klass: AnyClass, options: AnyRegisterClassOptions = {}):
|
|
|
486
524
|
markDerivedClass(klass);
|
|
487
525
|
installSignalOverrides(newType, methods);
|
|
488
526
|
applyInterfaceMixins(klass, adoptedTypes, inheritedNames);
|
|
489
|
-
installDeclaredSignalMethods(klass, signals.table
|
|
527
|
+
installDeclaredSignalMethods(klass, signals.table);
|
|
490
528
|
invokeClassInit(options, newType);
|
|
491
529
|
|
|
492
530
|
return klass;
|
|
@@ -836,8 +874,6 @@ function buildPropertyVfunc(
|
|
|
836
874
|
};
|
|
837
875
|
}
|
|
838
876
|
|
|
839
|
-
const canonicalSignalName = (name: string): string => name.replaceAll("_", "-");
|
|
840
|
-
|
|
841
877
|
function assertLowerCaseSignalName(klass: AnyClass, name: string): void {
|
|
842
878
|
if (!UPPER_CASE_PATTERN.test(name)) {
|
|
843
879
|
return;
|
|
@@ -946,72 +982,33 @@ function resolveDeclaredSignals(klass: AnyClass, signals: Record<string, SignalS
|
|
|
946
982
|
return { native, table };
|
|
947
983
|
}
|
|
948
984
|
|
|
949
|
-
function inheritedSignalMethod<T>(inherited: T | undefined, signal: string): T {
|
|
950
|
-
if (inherited === undefined) {
|
|
951
|
-
throw new Error(`Unknown signal '${signal}'`);
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
return inherited;
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
function installDeclaredConnect(
|
|
958
|
-
proto: SignalMethodHost,
|
|
959
|
-
findDeclared: (signal: string) => DeclaredSignalTypes | undefined,
|
|
960
|
-
): void {
|
|
961
|
-
const inheritedConnect = proto.connect;
|
|
962
|
-
|
|
963
|
-
proto.connect = function connect(
|
|
964
|
-
this: object,
|
|
965
|
-
signal: string,
|
|
966
|
-
handler: SignalHandler,
|
|
967
|
-
isAfter?: boolean,
|
|
968
|
-
): number {
|
|
969
|
-
if (findDeclared(signal) === undefined) {
|
|
970
|
-
return inheritedSignalMethod(inheritedConnect, signal).call(this, signal, handler, isAfter);
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
return connectClosureSignal(this, signal, handler, isAfter ?? false);
|
|
974
|
-
};
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
function installDeclaredEmit(
|
|
978
|
-
proto: SignalMethodHost,
|
|
979
|
-
findDeclared: (signal: string) => DeclaredSignalTypes | undefined,
|
|
980
|
-
): void {
|
|
981
|
-
const inheritedEmit = proto.emit;
|
|
982
|
-
|
|
983
|
-
proto.emit = function emit(this: object, sigName: string, ...args: unknown[]): unknown {
|
|
984
|
-
const declared = findDeclared(sigName);
|
|
985
|
-
|
|
986
|
-
if (declared === undefined) {
|
|
987
|
-
return inheritedSignalMethod(inheritedEmit, sigName).call(this, sigName, ...args);
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
return emitDeclaredSignal(this, sigName, declared, args);
|
|
991
|
-
};
|
|
992
|
-
}
|
|
993
|
-
|
|
994
985
|
function installDeclaredSignalMethods(
|
|
995
986
|
klass: AnyClass,
|
|
996
987
|
table: Map<string, DeclaredSignalTypes>,
|
|
997
|
-
definedNames: Set<string>,
|
|
998
988
|
): void {
|
|
999
989
|
if (table.size === 0) {
|
|
1000
990
|
return;
|
|
1001
991
|
}
|
|
1002
992
|
|
|
1003
|
-
const proto = klass.prototype as SignalMethodHost;
|
|
1004
|
-
|
|
1005
993
|
const findDeclared = (signal: string): DeclaredSignalTypes | undefined =>
|
|
1006
|
-
table.get(canonicalSignalName(
|
|
994
|
+
table.get(canonicalSignalName(signal));
|
|
1007
995
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
996
|
+
installSignalDispatch(klass, table.keys().toArray(), {
|
|
997
|
+
connect(instance, signal, handler, isAfter): number {
|
|
998
|
+
findDeclared(signal);
|
|
1011
999
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1000
|
+
return connectClosureSignal(instance, signal, handler, isAfter ?? false);
|
|
1001
|
+
},
|
|
1002
|
+
emit(instance, signal, args): unknown {
|
|
1003
|
+
const declared = findDeclared(signal);
|
|
1004
|
+
|
|
1005
|
+
if (declared === undefined) {
|
|
1006
|
+
throw new Error(`Unknown signal '${signal}'`);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
return emitDeclaredSignal(instance, signal, declared, args);
|
|
1010
|
+
},
|
|
1011
|
+
});
|
|
1015
1012
|
}
|
|
1016
1013
|
|
|
1017
1014
|
function toNativeInterface(binding: InterfaceVfuncBinding): NativeRegisterClassInterface {
|