2 Copyright (C) 2000-2003 SKYRIX Software AG
4 This file is part of OGo
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include "NGJavaScriptShadow.h"
24 #include "NGJavaScriptObjCClassInfo.h"
25 #include "NGJavaScriptObjectMappingContext.h"
26 #include <NGScripting/NGScriptLanguage.h>
30 static BOOL IsInPropDefMode = NO;
32 @interface NGJavaScriptShadow(Privates)
33 - (BOOL)_applyStaticDefs;
36 @implementation NGJavaScriptShadow
38 static NGScriptLanguage *jslang = nil;
40 static inline NGScriptLanguage *_JS(void) {
42 jslang = [[NGScriptLanguage languageWithName:@"javascript"] retain];
46 static void _finalize(JSContext *cx, JSObject *obj) {
47 NGJavaScriptShadow *self;
49 if ((self = JS_GetPrivate(cx, obj)) == NULL) {
50 //printf("finalized JS shadow ..\n");
53 NSLog(@"ERROR(%s): finalizing JS shadow j0x%p, "
54 @"still has a private o0x%p !!!",
55 __PRETTY_FUNCTION__, obj, self);
59 JSClass ObjCShadow_JSClass = {
61 JSCLASS_HAS_PRIVATE /* flags */,
70 /* Optionally non-null members start here. */
71 NULL, //JSGetObjectOps getObjectOps;
72 NULL, //JSCheckAccessOp checkAccess;
73 NULL, //JSNative call;
74 NULL, //JSNative construct;
75 NULL, //JSXDRObjectOp xdrObject;
76 NULL, //JSHasInstanceOp hasInstance;
80 + (void *)jsObjectClass {
81 return &ObjCShadow_JSClass;
84 static JSBool shadow_FuncDispatcher
85 (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
86 static JSBool shadow_setStaticProp
87 (JSContext *cx, JSObject *obj, jsval _id, jsval *vp);
88 static JSBool shadow_getStaticProp
89 (JSContext *cx, JSObject *obj, jsval _id, jsval *vp);
91 static NSMutableDictionary *classToInfo = nil;
93 static void relInfo(void) {
95 RELEASE(classToInfo); classToInfo = nil;
98 static NGJavaScriptObjCClassInfo *jsClassInfo(Class _class) {
99 NGJavaScriptObjCClassInfo *ci;
104 if (classToInfo == nil) {
105 classToInfo = [[NSMutableDictionary alloc] initWithCapacity:64];
109 if ((ci = [classToInfo objectForKey:_class]) == nil) {
110 ci = [[NGJavaScriptObjCClassInfo alloc]
112 setter:shadow_setStaticProp
113 getter:shadow_getStaticProp
114 caller:shadow_FuncDispatcher];
115 [classToInfo setObject:ci forKey:_class];
122 - (id)initWithHandle:(void *)_handle
123 inMappingContext:(NGObjectMappingContext *)_ctx
125 if ((self = [super initWithHandle:_handle inMappingContext:_ctx])) {
126 JS_SetPrivate(self->jscx, _handle, self);
132 if (NGJavaScriptBridge_TRACK_MEMORY) {
133 NSLog(@"%s: dealloc shadow o0x%p j0x%p ctx=0x%p jcx=0x%p",
134 __PRETTY_FUNCTION__, self, self->handle,
135 self->ctx, self->jscx);
139 JS_SetPrivate(self->jscx, self->handle, NULL);
144 - (void)setMasterObject:(id)_master {
145 if ((self->masterObject = _master)) {
146 if (![self _applyStaticDefs]) {
147 self->masterObject = nil;
148 NSLog(@"%s: resetted master object, because static defs could "
149 @"not be applied: %@", __PRETTY_FUNCTION__, _master);
153 if (NGJavaScriptBridge_TRACK_MEMORY) {
154 NSLog(@"%s: resetted shadow master (rc now %i)",
161 return self->masterObject;
163 - (void)invalidateShadow {
164 [self setMasterObject:nil];
167 - (BOOL)_applyStaticDefs {
168 NGJavaScriptObjCClassInfo *ci;
171 if (self->masterObject == nil)
174 ci = jsClassInfo([self->masterObject class]);
176 IsInPropDefMode = YES;
177 ok = [ci applyOnJSObject:self->handle inJSContext:self->jscx];
179 NSLog(@"ERROR(%s): couldn't apply static defs !", __PRETTY_FUNCTION__);
180 IsInPropDefMode = NO;
184 /* static definition declarations */
186 static JSBool shadow_setStaticProp
187 (JSContext *cx, JSObject *obj, jsval _id, jsval *vp)
189 NGJavaScriptObjCClassInfo *ci;
190 NGJavaScriptShadow *self;
194 if ((self = JS_GetPrivate(cx, obj)) == NULL)
197 if (self->masterObject == nil) {
198 NSLog(@"%s: master object was deallocated !", __PRETTY_FUNCTION__);
202 ci = jsClassInfo([self->masterObject class]);
203 NSCAssert(ci, @"missing class info ..");
205 sel = [ci setSelectorForPropertyId:&_id inJSContext:cx];
208 NSLog(@"%s: did not find selector for id !", __PRETTY_FUNCTION__);
212 value = [self->ctx objectForJSValue:vp];
213 [self->masterObject performSelector:sel withObject:value];
217 static JSBool shadow_getStaticProp
218 (JSContext *cx, JSObject *obj, jsval _id, jsval *vp)
220 NGJavaScriptObjCClassInfo *ci;
221 NGJavaScriptShadow *self;
225 if ((self = JS_GetPrivate(cx, obj)) == NULL) {
226 NSLog(@"%s: did not find private of JS shadow object !",
227 __PRETTY_FUNCTION__);
231 if (self->masterObject == nil) {
232 NSLog(@"%s: master object was deallocated !", __PRETTY_FUNCTION__);
236 ci = jsClassInfo([self->masterObject class]);
237 sel = [ci getSelectorForPropertyId:&_id inJSContext:cx];
240 NSLog(@"%s: did not find selector for id !", __PRETTY_FUNCTION__);
244 result = [self->masterObject performSelector:sel];
245 //NSLog(@"result is %@", result);
247 return [self->ctx jsValue:vp forObject:result]
252 static JSBool shadow_FuncDispatcher
253 (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
255 NGJavaScriptShadow *self;
257 const char *funcName;
264 NSException *exception;
267 if (JS_IsConstructing(cx))
268 obj = JS_GetParent(cx, obj);
271 if (JS_GetClass(obj) != &ObjCShadow_JSClass) {
272 NSLog(@"%s: invoked on invalid object class (eg using 'new' ?) !",
273 __PRETTY_FUNCTION__);
278 if ((self = JS_GetPrivate(cx, obj)) == NULL)
282 NSCAssert(JS_TypeOfValue(cx, argv[-2]) == JSTYPE_FUNCTION,
283 @"expected function in argv[-2] !");
286 funobj = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[-2]));
287 funcName = JS_GetFunctionName(funobj);
289 msgname = malloc(strlen(funcName) + 10);
290 strcpy(msgname, "_jsfunc_");
291 strcat(msgname, funcName);
292 strcat(msgname, ":");
293 #if APPLE_RUNTIME || NeXT_RUNTIME
294 sel = sel_getUid(msgname); /* TODO: should be registerName? */
296 sel = sel_get_any_uid(msgname);
300 args = calloc(argc, sizeof(id));
301 for (i = 0; i < argc; i++) {
303 [self->ctx objectForJSValue:&(argv[i])];
305 if (args[i] == nil) args[i] = [EONull null];
307 argArray = [NSArray arrayWithObjects:args count:argc];
311 argArray = [NSArray array];
314 NSLog(@"calling function '%s'(%s), %d args %@\n",
315 funcName, msgname, argc, argArray);
320 result = [self->masterObject performSelector:sel withObject:argArray];
321 retcode = [self->ctx jsValue:rval forObject:result] ? JS_TRUE : JS_FALSE;
324 exception = RETAIN(localException);
332 NSLog(@"%s: catched exception: %@", __PRETTY_FUNCTION__, exception);
337 if ([self->ctx jsValue:&exval forObject:[exception description]]) {
338 JS_SetPendingException(cx, exval);
341 NSLog(@"%s: couldn't get JS value for exception: %@",
342 __PRETTY_FUNCTION__, exception);
349 /* specialized calls */
351 - (id)callScriptFunction:(NSString *)_func {
352 return [_JS() callFunction:_func onObject:self];
354 - (id)callScriptFunction:(NSString *)_func withObject:(id)_obj {
355 return [_JS() callFunction:_func withArgument:_obj onObject:self];
357 - (BOOL)hasFunctionNamed:(NSString *)_func {
358 return [super hasFunctionNamed:_func];
361 - (id)evaluateScript:(NSString *)_script
362 source:(NSString *)_src line:(unsigned)_line
364 return [_JS() evaluateScript:_script onObject:self source:_src line:_line];
366 - (id)evaluateScript:(NSString *)_script {
367 return [self evaluateScript:_script source:@"<string>" line:0];
372 - (id)initWithCoder:(NSCoder *)_coder {
373 if ((self = [super initWithCoder:_coder])) {
374 [self setMasterObject:[_coder decodeObject]];
378 - (void)encodeWithCoder:(NSCoder *)_coder {
379 [super encodeWithCoder:_coder];
380 [_coder encodeObject:[self masterObject]];
383 @end /* NGJavaScriptShadow */