1 /* -*- mode: C; indent-tabs-mode: t; tab-width: 8; c-basic-offset: 2; -*- */
4 * This file is part of Seed, the GObject Introspection<->Javascript bindings.
6 * Seed is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation, either version 3 of
9 * the License, or (at your option) any later version.
10 * Seed is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with Seed. If not, see <http://www.gnu.org/licenses/>.
17 * Copyright (C) Robert Carr 2009 <carrr@rpi.edu>
20 #include "seed-private.h"
23 JSClassRef seed_native_callback_class;
26 seed_closure_finalize (JSObjectRef object)
28 SeedNativeClosure *privates =
29 (SeedNativeClosure *) JSObjectGetPrivate (object);
31 SEED_NOTE (FINALIZATION, "Finalizing closure object %p with "
32 "GIBaseInfo: %s \n", object,
33 g_base_info_get_name ((GIBaseInfo *) privates->info));
35 g_free (privates->cif->arg_types);
36 g_free (privates->cif);
37 g_callable_info_free_closure (privates->info, privates->closure);
38 g_base_info_unref ((GIBaseInfo *) privates->info);
40 JSValueUnprotect (eng->context, object);
44 seed_handle_closure (ffi_cif * cif, void *result, void **args, void *userdata)
46 SeedNativeClosure *privates = userdata;
49 JSValueRef return_value, exception = 0;
52 GITypeInfo *return_type;
55 GArgument rarg, return_arg;
56 JSContextRef ctx = JSGlobalContextCreateInGroup (context_group, 0);
57 GArgument *arg = &rarg;
60 seed_prepare_global_context (ctx);
62 SEED_NOTE (INVOCATION, "Invoking closure of type: %s \n",
63 g_base_info_get_name ((GIBaseInfo *) privates->info));
65 num_args = g_callable_info_get_n_args (privates->info);
66 return_type = g_callable_info_get_return_type (privates->info);
67 return_tag = g_type_info_get_tag (return_type);
68 jsargs = (JSValueRef *) g_newa (JSValueRef, num_args);
70 for (i = 0; i < num_args; i++)
73 arg_info = g_callable_info_get_arg (privates->info, i);
74 arg_type = g_arg_info_get_type (arg_info);
75 tag = g_type_info_get_tag (arg_type);
79 case GI_TYPE_TAG_BOOLEAN:
80 arg->v_boolean = *(gboolean *) args[i];
82 case GI_TYPE_TAG_INT8:
83 arg->v_int8 = *(gint8 *) args[i];
85 case GI_TYPE_TAG_UINT8:
86 arg->v_uint8 = *(guint8 *) args[i];
88 case GI_TYPE_TAG_INT16:
89 arg->v_int16 = *(gint16 *) args[i];
91 case GI_TYPE_TAG_UINT16:
92 arg->v_uint16 = *(guint16 *) args[i];
94 case GI_TYPE_TAG_INT32:
95 arg->v_int32 = *(gint32 *) args[i];
97 case GI_TYPE_TAG_UINT32:
98 arg->v_uint32 = *(guint32 *) args[i];
100 case GI_TYPE_TAG_LONG:
101 case GI_TYPE_TAG_INT64:
102 arg->v_int64 = *(glong *) args[i];
104 case GI_TYPE_TAG_ULONG:
105 case GI_TYPE_TAG_UINT64:
106 arg->v_uint64 = *(glong *) args[i];
108 case GI_TYPE_TAG_INT:
109 case GI_TYPE_TAG_SSIZE:
110 case GI_TYPE_TAG_SIZE:
111 arg->v_int32 = *(gint *) args[i];
113 case GI_TYPE_TAG_UINT:
114 arg->v_uint32 = *(guint *) args[i];
116 case GI_TYPE_TAG_FLOAT:
117 arg->v_float = *(gfloat *) args[i];
119 case GI_TYPE_TAG_DOUBLE:
120 arg->v_double = *(gdouble *) args[i];
122 case GI_TYPE_TAG_UTF8:
123 arg->v_string = *(gchar **) args[i];
125 case GI_TYPE_TAG_INTERFACE:
127 GIBaseInfo *interface;
128 GIInfoType interface_type;
130 interface = g_type_info_get_interface (arg_type);
131 interface_type = g_base_info_get_type (interface);
133 if (interface_type == GI_INFO_TYPE_OBJECT ||
134 interface_type == GI_INFO_TYPE_INTERFACE)
136 arg->v_pointer = *(gpointer *) args[i];
137 g_base_info_unref (interface);
141 else if (interface_type == GI_INFO_TYPE_ENUM ||
142 interface_type == GI_INFO_TYPE_FLAGS)
144 arg->v_double = *(double *) args[i];
145 g_base_info_unref (interface);
148 else if (interface_type == GI_INFO_TYPE_STRUCT)
150 arg->v_pointer = *(gpointer *) args[i];
151 g_base_info_unref (interface);
155 g_base_info_unref (interface);
157 case GI_TYPE_TAG_GLIST:
158 case GI_TYPE_TAG_GSLIST:
159 arg->v_pointer = *(gpointer *) args[i];
164 jsargs[i] = seed_gi_argument_make_js (ctx, arg, arg_type, 0);
165 seed_gi_release_in_arg (g_arg_info_get_ownership_transfer (arg_info),
167 g_base_info_unref ((GIBaseInfo *) arg_info);
168 g_base_info_unref ((GIBaseInfo *) arg_type);
171 return_value = (JSValueRef)
172 JSObjectCallAsFunction (ctx,
173 (JSObjectRef) privates->function, 0,
174 num_args, jsargs, &exception);
178 mes = seed_exception_to_string (ctx, exception);
179 g_warning ("Exception in closure marshal. %s \n", mes);
184 seed_gi_make_argument (ctx, (JSValueRef) return_value, return_type,
189 case GI_TYPE_TAG_BOOLEAN:
190 *(gboolean *) result = return_arg.v_boolean;
192 case GI_TYPE_TAG_INT8:
193 *(gint8 *) result = return_arg.v_int8;
195 case GI_TYPE_TAG_UINT8:
196 *(guint8 *) result = return_arg.v_uint8;
198 case GI_TYPE_TAG_INT16:
199 *(gint16 *) result = return_arg.v_int16;
201 case GI_TYPE_TAG_UINT16:
202 return_arg.v_uint16 = *(guint16 *) args[i];
204 case GI_TYPE_TAG_INT32:
205 *(gint32 *) result = return_arg.v_int32;
207 case GI_TYPE_TAG_UINT32:
208 *(guint32 *) result = return_arg.v_uint32;
210 case GI_TYPE_TAG_LONG:
211 case GI_TYPE_TAG_INT64:
212 *(glong *) result = return_arg.v_int64;
214 case GI_TYPE_TAG_ULONG:
215 case GI_TYPE_TAG_UINT64:
216 *(glong *) result = return_arg.v_uint64;
218 case GI_TYPE_TAG_INT:
219 case GI_TYPE_TAG_SSIZE:
220 case GI_TYPE_TAG_SIZE:
221 *(gint *) result = return_arg.v_int32;
223 case GI_TYPE_TAG_UINT:
224 *(guint *) result = return_arg.v_uint32;
226 case GI_TYPE_TAG_FLOAT:
227 *(gfloat *) result = return_arg.v_float;
229 case GI_TYPE_TAG_DOUBLE:
230 *(gdouble *) result = return_arg.v_double;
232 case GI_TYPE_TAG_UTF8:
233 *(gchar **) result = return_arg.v_string;
235 case GI_TYPE_TAG_INTERFACE:
237 GIBaseInfo *interface;
238 GIInfoType interface_type;
240 interface = g_type_info_get_interface (return_type);
241 interface_type = g_base_info_get_type (interface);
243 if (interface_type == GI_INFO_TYPE_OBJECT ||
244 interface_type == GI_INFO_TYPE_INTERFACE)
246 *(gpointer *) result = return_arg.v_pointer;
250 else if (interface_type == GI_INFO_TYPE_ENUM ||
251 interface_type == GI_INFO_TYPE_FLAGS)
253 *(double *) result = return_arg.v_double;
256 else if (interface_type == GI_INFO_TYPE_STRUCT)
258 *(gpointer *) result = return_arg.v_pointer;
262 case GI_TYPE_TAG_GLIST:
263 case GI_TYPE_TAG_GSLIST:
264 *(gpointer *) result = return_arg.v_pointer;
267 *(gpointer *) result = 0;
270 g_base_info_unref ((GIBaseInfo *) return_type);
271 JSGlobalContextRelease ((JSGlobalContextRef) ctx);
275 seed_make_native_closure (JSContextRef ctx,
276 GICallableInfo * info,
280 ffi_closure *closure;
281 ffi_type **arg_types;
282 GITypeInfo *return_type;
284 SeedNativeClosure *privates;
288 (JSObjectRef) seed_object_get_property (ctx, (JSObjectRef) function,
289 "__seed_native_closure");
291 && JSValueIsObjectOfClass (ctx, cached, seed_native_callback_class))
293 return (SeedNativeClosure *) JSObjectGetPrivate (cached);
296 num_args = g_callable_info_get_n_args (info);
297 return_type = g_callable_info_get_return_type (info);
298 arg_types = (ffi_type **) g_new0 (ffi_type *, num_args + 1);
299 cif = g_new0 (ffi_cif, 1);
301 privates = g_new0 (SeedNativeClosure, 1);
302 privates->info = (GICallableInfo *) g_base_info_ref ((GIBaseInfo *) info);
303 privates->function = function;
307 g_callable_info_prepare_closure (info, cif, seed_handle_closure,
309 privates->closure = closure;
311 JSValueProtect (ctx, function);
313 seed_object_set_property (ctx, (JSObjectRef) function,
314 "__seed_native_closure",
315 (JSValueRef) JSObjectMake (ctx,
316 seed_native_callback_class,
319 g_base_info_unref ((GIBaseInfo *) return_type);
325 closure_invalidated (gpointer data, GClosure * c)
327 SeedClosure *closure = (SeedClosure *) c;
329 SEED_NOTE (FINALIZATION, "Finalizing closure.");
330 if (closure->user_data
331 && !JSValueIsUndefined (eng->context, closure->user_data))
332 JSValueUnprotect (eng->context, closure->user_data);
333 if (!JSValueIsUndefined (eng->context, closure->function))
334 JSValueUnprotect (eng->context, closure->function);
336 g_free (closure->description);
341 seed_closure_get_callable (GClosure * c)
343 return ((SeedClosure *) c)->function;
347 seed_closure_invoke (GClosure * closure, JSValueRef * args, guint argc,
348 JSValueRef * exception)
350 JSContextRef ctx = JSGlobalContextCreateInGroup (context_group, 0);
351 JSValueRef *real_args = g_newa (JSValueRef, argc + 1);
355 seed_prepare_global_context (ctx);
356 for (i = 0; i < argc; i++)
357 real_args[i] = args[i];
359 ((SeedClosure *) closure)->user_data ? ((SeedClosure *) closure)->
360 user_data : JSValueMakeNull (ctx);
363 JSObjectCallAsFunction (ctx, ((SeedClosure *) closure)->function, NULL,
364 argc + 1, real_args, exception);
365 JSGlobalContextRelease ((JSGlobalContextRef) ctx);
371 seed_closure_invoke_with_context (JSContextRef ctx, GClosure * closure,
372 JSValueRef * args, guint argc,
373 JSValueRef * exception)
375 JSValueRef *real_args = g_newa (JSValueRef, argc + 1);
379 for (i = 0; i < argc; i++)
380 real_args[i] = args[i];
382 ((SeedClosure *) closure)->user_data ? ((SeedClosure *) closure)->
383 user_data : JSValueMakeNull (ctx);
386 JSObjectCallAsFunction (ctx, ((SeedClosure *) closure)->function, NULL,
387 argc + 1, real_args, exception);
393 seed_closure_new (JSContextRef ctx, JSObjectRef function,
394 JSObjectRef user_data, const gchar * description)
398 closure = g_closure_new_simple (sizeof (SeedClosure), 0);
399 g_closure_add_finalize_notifier (closure, 0, closure_invalidated);
400 g_closure_set_marshal (closure, seed_signal_marshal_func);
402 JSValueProtect (ctx, function);
403 ((SeedClosure *) closure)->function = function;
404 if (user_data && !JSValueIsNull (ctx, user_data))
406 ((SeedClosure *) closure)->user_data = user_data;
407 JSValueProtect (ctx, user_data);
411 ((SeedClosure *) closure)->description = g_strdup (description);
417 seed_closure_warn_exception (GClosure * c,
418 JSContextRef ctx, JSValueRef exception)
420 JSObjectRef callable = seed_closure_get_callable (c);
421 gchar *name = seed_value_to_string (ctx,
422 seed_object_get_property (ctx, callable,
425 gchar *mes = seed_exception_to_string (ctx, exception);
427 g_warning ("Exception in closure (%p) for %s (handler %s). %s", c,
428 ((SeedClosure *) c)->description,
429 *name == '\0' ? "[anonymous]" : name, mes);
435 JSClassDefinition seed_native_callback_def = {
436 0, /* Version, always 0 */
438 "seed_native_callback", /* Class Name */
439 0, /* Parent Class */
440 NULL, /* Static Values */
441 NULL, /* Static Functions */
443 seed_closure_finalize, /* Finalize */
444 NULL, /* Has Property */
445 NULL, /* Get Property */
446 NULL, /* Set Property */
447 NULL, /* Delete Property */
448 NULL, /* Get Property Names */
449 NULL, /* Call As Function */
450 NULL, /* Call As Constructor */
451 NULL, /* Has Instance */
452 NULL /* Convert To Type */
456 seed_closures_init (void)
458 seed_native_callback_class = JSClassCreate (&seed_native_callback_def);
459 JSClassRetain (seed_native_callback_class);