@gtkx/runtime 2.0.0-beta.1 → 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/dist/internal.d.ts +16 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +12 -0
- 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/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 +4 -2
- package/dist/properties.d.ts.map +1 -1
- package/dist/properties.js +69 -16
- 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 +102 -20
- 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 +75 -5
- package/dist/signal.js.map +1 -1
- package/dist/type.d.ts.map +1 -1
- package/dist/type.js +1 -1
- package/dist/type.js.map +1 -1
- package/package.json +4 -4
- package/src/internal.ts +41 -0
- package/src/listeners.ts +21 -26
- package/src/mixin.ts +55 -9
- package/src/object.ts +55 -5
- package/src/properties.ts +94 -17
- package/src/property-brand.ts +5 -0
- package/src/register-class.ts +296 -95
- package/src/registry.ts +4 -4
- package/src/signal-brand.ts +29 -0
- package/src/signal.ts +177 -6
- package/src/type.ts +1 -1
package/src/signal.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Descriptor, ExternalObject, Handle } from "@gtkx/native";
|
|
2
|
-
import { toCamelIdentifier, upperFirst } from "@gtkx/utils";
|
|
2
|
+
import { type AnyClass, toCamelIdentifier, upperFirst } from "@gtkx/utils";
|
|
3
|
+
import type { ResolvedSignalEmitMap, ResolvedSignalMap } from "./signal-brand.js";
|
|
3
4
|
import { type Arg, isCallerAllocatedArg, isInoutArg, isOutputArg } from "./arg.js";
|
|
4
5
|
import { bind } from "./bind.js";
|
|
5
6
|
import { wrapCallback } from "./callback.js";
|
|
@@ -19,7 +20,7 @@ import {
|
|
|
19
20
|
voidT,
|
|
20
21
|
} from "./descriptors.js";
|
|
21
22
|
import { LIB, VALUE_SIZE, VALUE_T } from "./library.js";
|
|
22
|
-
import { getHandle } from "./registry.js";
|
|
23
|
+
import { getClassType, getHandle, getInstanceType } from "./registry.js";
|
|
23
24
|
import { packTupleResult } from "./tuple.js";
|
|
24
25
|
import { TYPE_INVALID, type TypedClass, typeInterfaces, typeParent } from "./type.js";
|
|
25
26
|
import {
|
|
@@ -37,6 +38,55 @@ import {
|
|
|
37
38
|
/** Function invoked when a connected GObject signal is emitted. */
|
|
38
39
|
type SignalHandler = (...args: unknown[]) => unknown;
|
|
39
40
|
|
|
41
|
+
const isSignalHandler = (value: unknown): value is SignalHandler => typeof value === "function";
|
|
42
|
+
|
|
43
|
+
type DeclaredSignalMap<T> = T extends { __signals__?: infer TSignals } ? NonNullable<TSignals> : never;
|
|
44
|
+
type SignalMap<T> = ResolvedSignalMap<T, DeclaredSignalMap<T>>;
|
|
45
|
+
type SignalName<T> = Extract<keyof SignalMap<T>, string>;
|
|
46
|
+
type DeclaredSignalEmitMap<T> = T extends { __signalEmit__?: infer TSignals }
|
|
47
|
+
? NonNullable<TSignals>
|
|
48
|
+
: T extends { __signals__?: infer TSignals }
|
|
49
|
+
? {
|
|
50
|
+
[K in keyof NonNullable<TSignals>]: NonNullable<TSignals>[K] extends (
|
|
51
|
+
...args: infer TArgs
|
|
52
|
+
) => infer TResult
|
|
53
|
+
? { args: TArgs; result: TResult }
|
|
54
|
+
: never;
|
|
55
|
+
}
|
|
56
|
+
: never;
|
|
57
|
+
type SignalEmitMap<T> = ResolvedSignalEmitMap<T, DeclaredSignalEmitMap<T>>;
|
|
58
|
+
type SignalEmitName<T> = Extract<keyof SignalEmitMap<T>, string>;
|
|
59
|
+
type SignalEmitArguments<T, K extends SignalEmitName<T>> = SignalEmitMap<T>[K] extends {
|
|
60
|
+
args: infer TArgs extends unknown[];
|
|
61
|
+
}
|
|
62
|
+
? TArgs
|
|
63
|
+
: never;
|
|
64
|
+
type SignalEmitResult<T, K extends SignalEmitName<T>> = SignalEmitMap<T>[K] extends {
|
|
65
|
+
result: infer TResult;
|
|
66
|
+
}
|
|
67
|
+
? TResult
|
|
68
|
+
: never;
|
|
69
|
+
|
|
70
|
+
type SignalConnector = (
|
|
71
|
+
instance: object,
|
|
72
|
+
signal: string,
|
|
73
|
+
handler: SignalHandler,
|
|
74
|
+
isAfter?: boolean,
|
|
75
|
+
) => number;
|
|
76
|
+
type SignalEmitter = (instance: object, signal: string, args: unknown[]) => unknown;
|
|
77
|
+
type SignalDispatch = {
|
|
78
|
+
connect: SignalConnector;
|
|
79
|
+
emit: SignalEmitter;
|
|
80
|
+
};
|
|
81
|
+
type SignalDispatchSpec = {
|
|
82
|
+
connect: SignalConnector;
|
|
83
|
+
emit: SignalEmitter;
|
|
84
|
+
};
|
|
85
|
+
type PendingSignalDispatch = {
|
|
86
|
+
ownerType: bigint;
|
|
87
|
+
spec: SignalDispatchSpec;
|
|
88
|
+
};
|
|
89
|
+
|
|
40
90
|
type DeclaredSignalTypes = {
|
|
41
91
|
paramTypes: bigint[];
|
|
42
92
|
returnType?: bigint;
|
|
@@ -70,6 +120,8 @@ type EmitArg = Arg & {
|
|
|
70
120
|
};
|
|
71
121
|
|
|
72
122
|
const connectionTable: WeakMap<object, Map<string, Set<number>>> = new WeakMap();
|
|
123
|
+
const signalDispatchTable: Map<number, SignalDispatch> = new Map();
|
|
124
|
+
const pendingSignalDispatches: Map<string, PendingSignalDispatch[]> = new Map();
|
|
73
125
|
const gQuarkFromString = bind(LIB, "g_quark_from_string", [stringT("borrowed")], uint32T);
|
|
74
126
|
const gSignalLookup = bind(LIB, "g_signal_lookup", [stringT("borrowed"), biguint64T], uint32T);
|
|
75
127
|
const gSignalName = bind(LIB, "g_signal_name", [uint32T], stringT("borrowed"));
|
|
@@ -114,6 +166,15 @@ const getSignalBaseName = (signal: string): string => {
|
|
|
114
166
|
return detailIndex === -1 ? signal : signal.slice(0, detailIndex);
|
|
115
167
|
};
|
|
116
168
|
|
|
169
|
+
const canonicalSignalName = (signal: string): string => getSignalBaseName(signal).replaceAll("_", "-");
|
|
170
|
+
|
|
171
|
+
const canonicalDetailedSignalName = (signal: string): string => {
|
|
172
|
+
const detailIndex = signal.indexOf("::");
|
|
173
|
+
const base = canonicalSignalName(signal);
|
|
174
|
+
|
|
175
|
+
return detailIndex === -1 ? base : `${base}${signal.slice(detailIndex)}`;
|
|
176
|
+
};
|
|
177
|
+
|
|
117
178
|
function getSignalDetailQuark(signal: string): number {
|
|
118
179
|
const detailIndex = signal.indexOf("::");
|
|
119
180
|
|
|
@@ -180,7 +241,7 @@ function hasSignalListener(instance: object, signals?: string[]): boolean {
|
|
|
180
241
|
}
|
|
181
242
|
|
|
182
243
|
const names =
|
|
183
|
-
signals === undefined ? bySignal.keys().toArray() : signals.map((signal) =>
|
|
244
|
+
signals === undefined ? bySignal.keys().toArray() : signals.map((signal) => canonicalSignalName(signal));
|
|
184
245
|
|
|
185
246
|
return names.some((name) => {
|
|
186
247
|
const handlerIds = bySignal.get(name);
|
|
@@ -242,7 +303,7 @@ function connectSignal(instance: object, signal: string, spec: SignalConnectSpec
|
|
|
242
303
|
const key = `${String(type)}\0${getSignalBaseName(signal)}`;
|
|
243
304
|
const closure = newCCallbackClosure(key, callback, wrapped);
|
|
244
305
|
const handlerId = gSignalConnectClosure(getHandle(instance), signal, closure, isAfter) as number;
|
|
245
|
-
trackConnection(instance,
|
|
306
|
+
trackConnection(instance, canonicalSignalName(signal), handlerId);
|
|
246
307
|
|
|
247
308
|
return handlerId;
|
|
248
309
|
}
|
|
@@ -254,7 +315,7 @@ function overrideSignalClassClosure(type: bigint, signalId: number, handler: Sig
|
|
|
254
315
|
function connectClosureSignal(instance: object, signal: string, handler: SignalHandler, isAfter: boolean): number {
|
|
255
316
|
const closure = toClosure((...args: unknown[]) => Reflect.apply(handler, null, args.slice(1)));
|
|
256
317
|
const handlerId = gSignalConnectClosure(getHandle(instance), signal, closure, isAfter) as number;
|
|
257
|
-
trackConnection(instance,
|
|
318
|
+
trackConnection(instance, canonicalSignalName(signal), handlerId);
|
|
258
319
|
|
|
259
320
|
return handlerId;
|
|
260
321
|
}
|
|
@@ -350,19 +411,129 @@ function emitSignal(instance: object, signal: string, args: EmitArg[], returns?:
|
|
|
350
411
|
return packTupleResult(readEmitOutputs(reads), fromValue(returnValue), true);
|
|
351
412
|
}
|
|
352
413
|
|
|
414
|
+
function installSignalDispatch(
|
|
415
|
+
klass: AnyClass,
|
|
416
|
+
names: readonly string[],
|
|
417
|
+
spec: SignalDispatchSpec,
|
|
418
|
+
): void {
|
|
419
|
+
const ownerType = getClassType(klass);
|
|
420
|
+
|
|
421
|
+
for (const rawName of names) {
|
|
422
|
+
const name = canonicalSignalName(rawName);
|
|
423
|
+
pendingSignalDispatches.getOrInsertComputed(name, () => []).push({ ownerType, spec });
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const resolvePendingSignalDispatch = (signalId: number, name: string): SignalDispatch | undefined => {
|
|
428
|
+
const pending = pendingSignalDispatches.get(name) ?? [];
|
|
429
|
+
|
|
430
|
+
for (let index = pending.length - 1; index >= 0; index -= 1) {
|
|
431
|
+
const entry = pending[index];
|
|
432
|
+
|
|
433
|
+
if (
|
|
434
|
+
entry !== undefined &&
|
|
435
|
+
entry.ownerType !== TYPE_INVALID &&
|
|
436
|
+
signalIdFor(entry.ownerType, name) === signalId
|
|
437
|
+
) {
|
|
438
|
+
signalDispatchTable.set(signalId, entry.spec);
|
|
439
|
+
|
|
440
|
+
return entry.spec;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return undefined;
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
const signalDispatchFor = (instance: object, signal: string): SignalDispatch | undefined => {
|
|
448
|
+
const name = canonicalSignalName(signal);
|
|
449
|
+
const instanceType = getInstanceType(instance);
|
|
450
|
+
|
|
451
|
+
if (instanceType === TYPE_INVALID) {
|
|
452
|
+
return undefined;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const signalId = signalIdFor(instanceType, name);
|
|
456
|
+
|
|
457
|
+
if (signalId === 0) {
|
|
458
|
+
return undefined;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return signalDispatchTable.get(signalId) ?? resolvePendingSignalDispatch(signalId, name);
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
const connectDispatcherFor = (instance: object, signal: string): SignalConnector => {
|
|
465
|
+
const dispatch = signalDispatchFor(instance, signal);
|
|
466
|
+
|
|
467
|
+
if (dispatch === undefined) {
|
|
468
|
+
throw new TypeError("connectSignal: unknown signal");
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return dispatch.connect;
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
const emitDispatcherFor = (instance: object, signal: string): SignalEmitter => {
|
|
475
|
+
const dispatch = signalDispatchFor(instance, signal);
|
|
476
|
+
|
|
477
|
+
if (dispatch === undefined) {
|
|
478
|
+
throw new TypeError("emitSignal: unknown signal");
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return dispatch.emit;
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
function signalConnect<T extends object, K extends SignalName<NoInfer<T>>>(
|
|
485
|
+
instance: T,
|
|
486
|
+
signal: K,
|
|
487
|
+
handler: SignalMap<NoInfer<T>>[K],
|
|
488
|
+
isAfter?: boolean,
|
|
489
|
+
): number {
|
|
490
|
+
return connectSignalByName(instance, signal, handler, isAfter);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function connectSignalByName(
|
|
494
|
+
instance: object,
|
|
495
|
+
signal: string,
|
|
496
|
+
handler: unknown,
|
|
497
|
+
isAfter?: boolean,
|
|
498
|
+
): number {
|
|
499
|
+
if (!isSignalHandler(handler)) {
|
|
500
|
+
throw new TypeError("connectSignal: handler must be a function");
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return connectDispatcherFor(instance, signal)(instance, signal, handler, isAfter);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function emitSignalByName(instance: object, signal: string, args: unknown[]): unknown {
|
|
507
|
+
return emitDispatcherFor(instance, signal)(instance, signal, args);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function signalEmit<T extends object, K extends SignalEmitName<NoInfer<T>>>(
|
|
511
|
+
instance: T,
|
|
512
|
+
signal: K,
|
|
513
|
+
...args: SignalEmitArguments<NoInfer<T>, K>
|
|
514
|
+
): SignalEmitResult<NoInfer<T>, K> {
|
|
515
|
+
return emitSignalByName(instance, signal, args) as SignalEmitResult<NoInfer<T>, K>;
|
|
516
|
+
}
|
|
517
|
+
|
|
353
518
|
export {
|
|
519
|
+
canonicalDetailedSignalName,
|
|
520
|
+
canonicalSignalName,
|
|
354
521
|
signalForHandlerName,
|
|
355
522
|
getSignalBaseName,
|
|
356
523
|
signalIdFor,
|
|
357
524
|
connectClosureSignal,
|
|
358
525
|
connectSignal,
|
|
526
|
+
connectSignalByName,
|
|
359
527
|
type DeclaredSignalTypes,
|
|
360
528
|
disconnectSignal,
|
|
361
529
|
emitDeclaredSignal,
|
|
362
530
|
emitSignal,
|
|
531
|
+
emitSignalByName,
|
|
363
532
|
hasSignalListener,
|
|
364
533
|
isSignalHandlerConnected,
|
|
534
|
+
installSignalDispatch,
|
|
365
535
|
overrideSignalClassClosure,
|
|
366
|
-
|
|
536
|
+
signalConnect,
|
|
537
|
+
signalEmit,
|
|
367
538
|
type SignalHandler,
|
|
368
539
|
};
|
package/src/type.ts
CHANGED
|
@@ -86,7 +86,7 @@ const TYPE_VARIANT: bigint = typeFromName("GVariant");
|
|
|
86
86
|
/** GType tag for a Unicode character stored as `guint`. */
|
|
87
87
|
const TYPE_UNICHAR: bigint = typeFromName("guint");
|
|
88
88
|
const getErrorType: () => bigint = lazyType("GError");
|
|
89
|
-
const getStrvType
|
|
89
|
+
const getStrvType = (): bigint => resolveType(LIB, "g_strv_get_type");
|
|
90
90
|
|
|
91
91
|
const PLAIN_DESCRIPTOR_TYPES: Partial<Record<Descriptor["kind"], bigint>> = {
|
|
92
92
|
boolean: TYPE_BOOLEAN,
|