JSObject* gjs_boxed_from_c_struct(JSContext *context, GIStructInfo *info, void *gboxed, GjsBoxedCreationFlags flags) { JSObject *obj; JSObject *proto; Boxed *priv; Boxed *proto_priv; if (gboxed == NULL) return NULL; gjs_debug_marshal(GJS_DEBUG_GBOXED, "Wrapping struct %s %p with JSObject", g_base_info_get_name((GIBaseInfo *)info), gboxed); proto = gjs_lookup_boxed_prototype(context, info); proto_priv = priv_from_js(context, proto); obj = JS_NewObjectWithGivenProto(context, JS_GET_CLASS(context, proto), proto, gjs_get_import_global (context)); GJS_INC_COUNTER(boxed); priv = g_slice_new0(Boxed); *priv = *proto_priv; g_base_info_ref( (GIBaseInfo*) priv->info); JS_SetPrivate(context, obj, priv); if ((flags & GJS_BOXED_CREATION_NO_COPY) != 0) { /* we need to create a JS Boxed which references the * original C struct, not a copy of it. Used for * G_SIGNAL_TYPE_STATIC_SCOPE */ priv->gboxed = gboxed; priv->not_owning_gboxed = TRUE; } else { if (priv->gtype != G_TYPE_NONE && g_type_is_a (priv->gtype, G_TYPE_BOXED)) { priv->gboxed = g_boxed_copy(priv->gtype, gboxed); } else if (priv->gtype == G_TYPE_VARIANT) { priv->gboxed = g_variant_ref_sink (gboxed); } else if (priv->can_allocate_directly) { boxed_new_direct(priv); memcpy(priv->gboxed, gboxed, g_struct_info_get_size (priv->info)); } else { gjs_throw(context, "Can't create a Javascript object for %s; no way to copy", g_base_info_get_name( (GIBaseInfo*) priv->info)); } } return obj; }
static JSBool get_nested_interface_object (JSContext *context, JSObject *parent_obj, Boxed *parent_priv, GIFieldInfo *field_info, GITypeInfo *type_info, GIBaseInfo *interface_info, jsval *value) { JSObject *obj; JSObject *proto; int offset; Boxed *priv; Boxed *proto_priv; if (!struct_is_simple ((GIStructInfo *)interface_info)) { gjs_throw(context, "Reading field %s.%s is not supported", g_base_info_get_name ((GIBaseInfo *)parent_priv->info), g_base_info_get_name ((GIBaseInfo *)field_info)); return JS_FALSE; } proto = gjs_lookup_boxed_prototype(context, (GIBoxedInfo*) interface_info); proto_priv = priv_from_js(context, proto); offset = g_field_info_get_offset (field_info); obj = JS_NewObjectWithGivenProto(context, JS_GET_CLASS(context, proto), proto, gjs_get_import_global (context)); if (obj == NULL) return JS_FALSE; GJS_INC_COUNTER(boxed); priv = g_slice_new0(Boxed); JS_SetPrivate(context, obj, priv); priv->info = (GIBoxedInfo*) interface_info; g_base_info_ref( (GIBaseInfo*) priv->info); priv->gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo*) interface_info); priv->can_allocate_directly = proto_priv->can_allocate_directly; /* A structure nested inside a parent object; doesn't have an independent allocation */ priv->gboxed = ((char *)parent_priv->gboxed) + offset; priv->not_owning_gboxed = TRUE; /* We never actually read the reserved slot, but we put the parent object * into it to hold onto the parent object. */ JS_SetReservedSlot(context, obj, 0, OBJECT_TO_JSVAL (parent_obj)); *value = OBJECT_TO_JSVAL(obj); return JS_TRUE; }
JSClass* gjs_lookup_boxed_class(JSContext *context, GIBoxedInfo *info) { JSObject *prototype; prototype = gjs_lookup_boxed_prototype(context, info); return JS_GET_CLASS(context, prototype); }
static JSBool set_nested_interface_object (JSContext *context, Boxed *parent_priv, GIFieldInfo *field_info, GITypeInfo *type_info, GIBaseInfo *interface_info, jsval value) { JSObject *proto; int offset; Boxed *proto_priv; Boxed *source_priv; if (!struct_is_simple ((GIStructInfo *)interface_info)) { gjs_throw(context, "Writing field %s.%s is not supported", g_base_info_get_name ((GIBaseInfo *)parent_priv->info), g_base_info_get_name ((GIBaseInfo *)field_info)); return JS_FALSE; } proto = gjs_lookup_boxed_prototype(context, (GIBoxedInfo*) interface_info); proto_priv = priv_from_js(context, proto); /* If we can't directly copy from the source object we need * to construct a new temporary object. */ if (!boxed_get_copy_source(context, proto_priv, value, &source_priv)) { JSObject *tmp_object = gjs_construct_object_dynamic(context, proto, 1, &value); if (!tmp_object) return JS_FALSE; source_priv = priv_from_js(context, tmp_object); if (!source_priv) return JS_FALSE; } offset = g_field_info_get_offset (field_info); memcpy(((char *)parent_priv->gboxed) + offset, source_priv->gboxed, g_struct_info_get_size (source_priv->info)); return JS_TRUE; }
JSBool gjs_define_error_class(JSContext *context, JSObject *in_object, GIEnumInfo *info, JSObject **constructor_p, JSObject **prototype_p) { const char *constructor_name; GIBoxedInfo *glib_error_info; JSObject *prototype, *parent_proto; JSObject *constructor; jsval value; Error *priv; /* See the comment in gjs_define_boxed_class() for an * explanation of how this all works; Error is pretty much the * same as Boxed (except that we inherit from GLib.Error). */ constructor_name = g_base_info_get_name( (GIBaseInfo*) info); if (gjs_object_get_property(context, in_object, constructor_name, &value)) { JSObject *constructor; if (!JSVAL_IS_OBJECT(value)) { gjs_throw(context, "Existing property '%s' does not look like a constructor", constructor_name); return JS_FALSE; } constructor = JSVAL_TO_OBJECT(value); gjs_object_get_property(context, constructor, "prototype", &value); if (!JSVAL_IS_OBJECT(value)) { gjs_throw(context, "error %s prototype property does not appear to exist or has wrong type", constructor_name); return JS_FALSE; } else { if (prototype_p) *prototype_p = JSVAL_TO_OBJECT(value); if (constructor_p) *constructor_p = constructor; return JS_TRUE; } } g_irepository_require(NULL, "GLib", "2.0", 0, NULL); glib_error_info = (GIBoxedInfo*) g_irepository_find_by_name(NULL, "GLib", "Error"); parent_proto = gjs_lookup_boxed_prototype(context, glib_error_info); g_base_info_unref((GIBaseInfo*)glib_error_info); prototype = gjs_init_class_dynamic(context, in_object, parent_proto, g_base_info_get_namespace( (GIBaseInfo*) info), constructor_name, &gjs_error_class, gjs_error_constructor, /* number of constructor args (less can be passed) */ 1, /* props of prototype */ &gjs_error_proto_props[0], /* funcs of prototype */ &gjs_error_proto_funcs[0], /* props of constructor, MyConstructor.myprop */ NULL, /* funcs of constructor, MyConstructor.myfunc() */ &gjs_error_constructor_funcs[0]); if (prototype == NULL) { gjs_log_exception(context, NULL); gjs_fatal("Can't init class %s", constructor_name); } g_assert(gjs_object_has_property(context, in_object, constructor_name)); GJS_INC_COUNTER(gerror); priv = g_slice_new0(Error); priv->info = info; g_base_info_ref( (GIBaseInfo*) priv->info); priv->domain = g_quark_from_string (g_enum_info_get_error_domain(priv->info)); JS_SetPrivate(context, prototype, priv); gjs_debug(GJS_DEBUG_GBOXED, "Defined class %s prototype is %p class %p in object %p", constructor_name, prototype, JS_GET_CLASS(context, prototype), in_object); constructor = NULL; gjs_object_get_property(context, in_object, constructor_name, &value); if (!JSVAL_IS_VOID(value)) { if (!JSVAL_IS_OBJECT(value)) { gjs_throw(context, "Property '%s' does not look like a constructor", constructor_name); return JS_FALSE; } } constructor = JSVAL_TO_OBJECT(value); gjs_define_enum_values(context, constructor, priv->info); if (constructor_p) *constructor_p = constructor; if (prototype_p) *prototype_p = prototype; return JS_TRUE; }