Skip to content

Commit f9762a3

Browse files
committed
finish addMethod API
1 parent dcf2fb2 commit f9762a3

File tree

5 files changed

+79
-45
lines changed

5 files changed

+79
-45
lines changed

examples/appkit.js

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,10 @@ export class ApplicationDelegate extends NSObject {
1313
}
1414

1515
running = true;
16-
1716
/**
18-
* @param {NSNotification} _notification
17+
* @type {Window | null}
1918
*/
20-
applicationDidFinishLaunching(_notification) {
21-
this.window = Window.new();
22-
23-
NSApp.activateIgnoringOtherApps(false);
24-
25-
NSApp.stop(this);
26-
27-
const loop = () => {
28-
const event = NSApp.nextEventMatchingMaskUntilDateInModeDequeue(
29-
NSEventMask.Any,
30-
null,
31-
"kCFRunLoopDefaultMode",
32-
true,
33-
);
34-
35-
if (event != null) {
36-
NSApp.sendEvent(event);
37-
}
38-
39-
if (this.running) {
40-
setTimeout(loop, 10);
41-
}
42-
};
43-
44-
setTimeout(loop, 0);
45-
46-
setTimeout(() => {
47-
console.log("[setTimeout] after 2 seconds");
48-
}, 2000);
49-
}
19+
window = null;
5020

5121
/**
5222
* @param {NSNotification} _notification
@@ -167,5 +137,46 @@ export class Window extends NSWindow {
167137
const NSApp = NSApplication.sharedApplication;
168138

169139
NSApp.setActivationPolicy(NSApplicationActivationPolicy.Regular);
170-
NSApp.delegate = ApplicationDelegate.new();
140+
141+
// Class is lazily initialized when first used
142+
const delegate = ApplicationDelegate.new();
143+
144+
// Add a method to the delegate class after it has been registered with the runtime,
145+
// dynamically.
146+
interop.addMethod(
147+
ApplicationDelegate,
148+
function applicationDidFinishLaunching(_notification) {
149+
this.window = Window.new();
150+
151+
NSApp.activateIgnoringOtherApps(false);
152+
153+
NSApp.stop(this);
154+
155+
const loop = () => {
156+
const event = NSApp.nextEventMatchingMaskUntilDateInModeDequeue(
157+
NSEventMask.Any,
158+
null,
159+
"kCFRunLoopDefaultMode",
160+
true,
161+
);
162+
163+
if (event != null) {
164+
NSApp.sendEvent(event);
165+
}
166+
167+
if (this.running) {
168+
setTimeout(loop, 10);
169+
}
170+
};
171+
172+
setTimeout(loop, 0);
173+
174+
setTimeout(() => {
175+
console.log("[setTimeout] after 2 seconds");
176+
}, 2000);
177+
},
178+
);
179+
180+
NSApp.delegate = delegate;
181+
171182
NSApp.run();

lib/types.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,16 @@ declare global {
9393

9494
export type Enum<_T extends Record<string, number>> = number;
9595

96+
export function addMethod<
97+
T extends abstract new (...args: unknown[]) => unknown,
98+
>(
99+
constructor: T,
100+
method: (this: InstanceType<T>, ...args: unknown[]) => unknown,
101+
): void;
102+
export function addProtocol(
103+
constructor: unknown,
104+
protocol: PointerObject,
105+
): void;
96106
export function adopt(ptr: Pointer): Pointer;
97107
export function free(ptr: Pointer): void;
98108
export function sizeof(obj: unknown): number;

src/ClassBuilder.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@
109109
!findMethod->second.classMethod) {
110110
return &findMethod->second.methodOrGetter;
111111
}
112-
// return processProtocols(protocol->protocols);
112+
return processProtocols(protocol->protocols);
113113
}
114114
return (MethodDescriptor *)nullptr;
115115
};

src/Closure.mm

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ void JSIMP(ffi_cif *cif, void *ret, void *args[], void *data) {
3434
}
3535

3636
napi_value func;
37-
napi_get_named_property(env, thisArg, closure->propertyName.c_str(), &func);
37+
if (closure->func != nullptr) {
38+
func = get_ref_value(env, closure->func);
39+
} else {
40+
napi_get_named_property(env, thisArg, closure->propertyName.c_str(), &func);
41+
}
3842

3943
napi_valuetype funcType;
4044
napi_typeof(env, func, &funcType);

src/Interop.mm

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -253,22 +253,29 @@ napi_value interop_addMethod(napi_env env, napi_callback_info info) {
253253
napi_throw_error(env, nullptr, "Invalid class");
254254
return nullptr;
255255
}
256+
ObjCBridgeState *bridgeState = ObjCBridgeState::InstanceData(env);
257+
builder = (ClassBuilder *)bridgeState->classesByPointer[(id)builder];
256258

257259
napi_value name;
258260
napi_get_named_property(env, argv[1], "name", &name);
259261

260-
static char funcNameBuf[512];
261-
napi_get_value_string_utf8(env, name, funcNameBuf, 512, nullptr);
262-
std::string funcName = funcNameBuf;
262+
if (builder->isFinal) {
263+
static char funcNameBuf[512];
264+
napi_get_value_string_utf8(env, name, funcNameBuf, 512, nullptr);
265+
std::string funcName = funcNameBuf;
263266

264-
MethodDescriptor *desc = builder->lookupMethodDescriptor(funcName);
265-
if (desc == nullptr) {
266-
napi_throw_error(env, nullptr, "Invalid method, descriptor not found");
267-
return nullptr;
268-
}
269-
270-
builder->addMethod(funcName, desc, name, argv[1]);
267+
MethodDescriptor *desc = builder->lookupMethodDescriptor(funcName);
268+
if (desc == nullptr) {
269+
napi_throw_error(env, nullptr, "Invalid method, descriptor not found");
270+
return nullptr;
271+
}
271272

273+
builder->addMethod(funcName, desc, name, argv[1]);
274+
} else {
275+
napi_set_property(env, get_ref_value(env, builder->prototype), name,
276+
argv[1]);
277+
}
278+
272279
return nullptr;
273280
}
274281

@@ -283,6 +290,8 @@ napi_value interop_addProtocol(napi_env env, napi_callback_info info) {
283290
napi_throw_error(env, nullptr, "Invalid class");
284291
return nullptr;
285292
}
293+
ObjCBridgeState *bridgeState = ObjCBridgeState::InstanceData(env);
294+
builder = (ClassBuilder *)bridgeState->classesByPointer[(id)builder];
286295

287296
ObjCProtocol *proto = nullptr;
288297
napi_unwrap(env, argv[1], (void **)&proto);

0 commit comments

Comments
 (0)