void * _pygi_boxed_alloc (GIBaseInfo *info, gsize *size_out) { gsize size; /* FIXME: Remove when bgo#622711 is fixed */ if (g_registered_type_info_get_g_type (info) == G_TYPE_VALUE) { size = sizeof (GValue); } else { switch (g_base_info_get_type (info)) { case GI_INFO_TYPE_UNION: size = g_union_info_get_size ( (GIUnionInfo *) info); break; case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: size = g_struct_info_get_size ( (GIStructInfo *) info); break; default: PyErr_Format (PyExc_TypeError, "info should be Boxed or Union, not '%d'", g_base_info_get_type (info)); return NULL; } } if( size_out != NULL) *size_out = size; return g_slice_alloc0 (size); }
static PyObject * _wrap_g_registered_type_info_get_g_type (PyGIBaseInfo *self) { GType type; type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) self->info); return pyg_type_wrapper_new (type); }
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; }
void lgi_type_get_repotype (lua_State *L, GType gtype, GIBaseInfo *info) { luaL_checkstack (L, 4, ""); /* Get repo-index table. */ lua_pushlightuserdata (L, &repo_index); lua_rawget (L, LUA_REGISTRYINDEX); /* Prepare gtype, if not given directly. */ if (gtype == G_TYPE_INVALID && info && GI_IS_REGISTERED_TYPE_INFO (info)) { gtype = g_registered_type_info_get_g_type (info); if (gtype == G_TYPE_NONE) gtype = G_TYPE_INVALID; } /* First of all, check direct indexing of repo-index by gtype, should be fastest. */ if (gtype != G_TYPE_INVALID) { lua_pushlightuserdata (L, (gpointer) gtype); lua_rawget (L, -2); } else lua_pushnil (L); if (lua_isnil (L, -1)) { /* Not indexed yet. Try to lookup by name - this works when lazy-loaded repo tables are not loaded yet. */ if (!info && gtype != G_TYPE_INVALID) { info = g_irepository_find_by_gtype (NULL, gtype); lgi_gi_info_new (L, info); } else /* Keep stack balanced as in the previous 'if' branch. */ lua_pushnil (L); if (info) { lua_pushlightuserdata (L, &repo); lua_rawget (L, LUA_REGISTRYINDEX); lua_getfield (L, -1, g_base_info_get_namespace (info)); lua_getfield (L, -1, g_base_info_get_name (info)); lua_replace (L, -5); lua_pop (L, 3); } else lua_pop (L, 1); } lua_replace (L, -2); }
static void boxed_fill_prototype_info(Boxed *priv) { int i, n_methods; int first_constructor = -1; priv->gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info); priv->zero_args_constructor = -1; priv->default_constructor = -1; if (priv->gtype != G_TYPE_NONE) { /* If the structure is registered as a boxed, we can create a new instance by * looking for a zero-args constructor and calling it; constructors don't * really make sense for non-boxed types, since there is no memory management * for the return value. */ n_methods = g_struct_info_get_n_methods(priv->info); for (i = 0; i < n_methods; ++i) { GIFunctionInfo *func_info; GIFunctionInfoFlags flags; func_info = g_struct_info_get_method(priv->info, i); flags = g_function_info_get_flags(func_info); if ((flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0) { if (first_constructor < 0) first_constructor = i; if (priv->zero_args_constructor < 0 && g_callable_info_get_n_args((GICallableInfo*) func_info) == 0) priv->zero_args_constructor = i; if (priv->default_constructor < 0 && strcmp(g_base_info_get_name ((GIBaseInfo*) func_info), "new") == 0) priv->default_constructor = i; } g_base_info_unref((GIBaseInfo*) func_info); } if (priv->default_constructor < 0) priv->default_constructor = priv->zero_args_constructor; if (priv->default_constructor < 0) priv->default_constructor = first_constructor; } }
static void seed_gi_importer_handle_iface(JSContextRef ctx, JSObjectRef namespace_ref, GIObjectInfo* info, JSValueRef* exception) { GType type; type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*) info); if (type != 0) { GIFunctionInfo* finfo; GIFunctionInfoFlags flags; JSObjectRef constructor_ref; guint i, n_methods; constructor_ref = JSObjectMake(ctx, gobject_constructor_class, (gpointer) type); seed_object_set_property(ctx, constructor_ref, "type", seed_value_from_long(ctx, type, exception)); n_methods = g_interface_info_get_n_methods(info); for (i = 0; i < n_methods; i++) { finfo = g_interface_info_get_method(info, i); flags = g_function_info_get_flags(finfo); if (!(flags & GI_FUNCTION_IS_METHOD)) { seed_gobject_define_property_from_function_info(ctx, finfo, constructor_ref, FALSE); } else { g_base_info_unref((GIBaseInfo*) finfo); } } seed_object_set_property(ctx, namespace_ref, g_base_info_get_name((GIBaseInfo*) info), constructor_ref); seed_object_set_property(ctx, constructor_ref, "prototype", seed_gobject_get_prototype_for_gtype(type)); } }
static void rb_gi_in_argument_free_interface(GIArgument *argument, GITypeInfo *type_info) { GIBaseInfo *interface_info; GIInfoType interface_type; interface_info = g_type_info_get_interface(type_info); interface_type = g_base_info_get_type(interface_info); if (interface_type == GI_INFO_TYPE_STRUCT) { GType gtype; gtype = g_registered_type_info_get_g_type(interface_info); if (gtype == G_TYPE_VALUE) { GValue *gvalue = argument->v_pointer; g_value_unset(gvalue); xfree(argument->v_pointer); } } g_base_info_unref(interface_info); }
void _pygi_argument_release (GIArgument *arg, GITypeInfo *type_info, GITransfer transfer, GIDirection direction) { GITypeTag type_tag; gboolean is_out = (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT); type_tag = g_type_info_get_tag (type_info); switch (type_tag) { case GI_TYPE_TAG_VOID: /* Don't do anything, it's transparent to the C side */ break; case GI_TYPE_TAG_BOOLEAN: case GI_TYPE_TAG_INT8: case GI_TYPE_TAG_UINT8: case GI_TYPE_TAG_INT16: case GI_TYPE_TAG_UINT16: case GI_TYPE_TAG_INT32: case GI_TYPE_TAG_UINT32: case GI_TYPE_TAG_INT64: case GI_TYPE_TAG_UINT64: case GI_TYPE_TAG_FLOAT: case GI_TYPE_TAG_DOUBLE: case GI_TYPE_TAG_GTYPE: case GI_TYPE_TAG_UNICHAR: break; case GI_TYPE_TAG_FILENAME: case GI_TYPE_TAG_UTF8: /* With allow-none support the string could be NULL */ if ((arg->v_string != NULL && (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)) || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { g_free (arg->v_string); } break; case GI_TYPE_TAG_ARRAY: { GArray *array; gsize i; if (arg->v_pointer == NULL) { return; } array = arg->v_pointer; if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { GITypeInfo *item_type_info; GITransfer item_transfer; item_type_info = g_type_info_get_param_type (type_info, 0); item_transfer = direction == GI_DIRECTION_IN ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING; /* Free the items */ for (i = 0; i < array->len; i++) { GIArgument *item; item = &_g_array_index (array, GIArgument, i); _pygi_argument_release (item, item_type_info, item_transfer, direction); } g_base_info_unref ( (GIBaseInfo *) item_type_info); } if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { g_array_free (array, TRUE); } break; } case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *info; GIInfoType info_type; info = g_type_info_get_interface (type_info); info_type = g_base_info_get_type (info); switch (info_type) { case GI_INFO_TYPE_CALLBACK: /* TODO */ break; case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: { GType type; if (arg->v_pointer == NULL) { return; } type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); if (g_type_is_a (type, G_TYPE_VALUE)) { GValue *value; value = arg->v_pointer; if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { g_value_unset (value); } if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { g_slice_free (GValue, value); } } else if (g_type_is_a (type, G_TYPE_CLOSURE)) { if (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) { g_closure_unref (arg->v_pointer); } } else if (info_type == GI_INFO_TYPE_STRUCT && g_struct_info_is_foreign ((GIStructInfo*) info)) { if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING) { pygi_struct_foreign_release (info, arg->v_pointer); } } else if (g_type_is_a (type, G_TYPE_BOXED)) { } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) { g_warn_if_fail (!g_type_info_is_pointer (type_info) || transfer == GI_TRANSFER_NOTHING); } break; } case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: break; case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: if (arg->v_pointer == NULL) { return; } if (is_out && transfer == GI_TRANSFER_EVERYTHING) { g_object_unref (arg->v_pointer); } break; default: g_assert_not_reached(); } g_base_info_unref (info); break; } case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: { GSList *list; if (arg->v_pointer == NULL) { return; } list = arg->v_pointer; if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { GITypeInfo *item_type_info; GITransfer item_transfer; GSList *item; item_type_info = g_type_info_get_param_type (type_info, 0); g_assert (item_type_info != NULL); item_transfer = direction == GI_DIRECTION_IN ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING; /* Free the items */ for (item = list; item != NULL; item = g_slist_next (item)) { _pygi_argument_release ( (GIArgument *) &item->data, item_type_info, item_transfer, direction); } g_base_info_unref ( (GIBaseInfo *) item_type_info); } if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { if (type_tag == GI_TYPE_TAG_GLIST) { g_list_free ( (GList *) list); } else { /* type_tag == GI_TYPE_TAG_GSLIST */ g_slist_free (list); } } break; } case GI_TYPE_TAG_GHASH: { GHashTable *hash_table; if (arg->v_pointer == NULL) { return; } hash_table = arg->v_pointer; if (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) { /* We created the table without a destroy function, so keys and * values need to be released. */ GITypeInfo *key_type_info; GITypeInfo *value_type_info; GITransfer item_transfer; GHashTableIter hash_table_iter; gpointer key; gpointer value; key_type_info = g_type_info_get_param_type (type_info, 0); g_assert (key_type_info != NULL); value_type_info = g_type_info_get_param_type (type_info, 1); g_assert (value_type_info != NULL); if (direction == GI_DIRECTION_IN) { item_transfer = GI_TRANSFER_NOTHING; } else { item_transfer = GI_TRANSFER_EVERYTHING; } g_hash_table_iter_init (&hash_table_iter, hash_table); while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) { _pygi_argument_release ( (GIArgument *) &key, key_type_info, item_transfer, direction); _pygi_argument_release ( (GIArgument *) &value, value_type_info, item_transfer, direction); } g_base_info_unref ( (GIBaseInfo *) key_type_info); g_base_info_unref ( (GIBaseInfo *) value_type_info); } else if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_CONTAINER) { /* Be careful to avoid keys and values being freed if the * callee gave a destroy function. */ g_hash_table_steal_all (hash_table); } if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { g_hash_table_unref (hash_table); } break; } case GI_TYPE_TAG_ERROR: { GError *error; if (arg->v_pointer == NULL) { return; } error = * (GError **) arg->v_pointer; if (error != NULL) { g_error_free (error); } g_slice_free (GError *, arg->v_pointer); break; } } }
static VALUE interface_to_ruby(GIArgument *argument, GITypeInfo *type_info) { VALUE rb_interface; GIBaseInfo *interface_info; GIInfoType interface_type; GType gtype; interface_info = g_type_info_get_interface(type_info); interface_type = g_base_info_get_type(interface_info); gtype = g_registered_type_info_get_g_type(interface_info); switch (interface_type) { case GI_INFO_TYPE_INVALID: rb_raise(rb_eNotImpError, "TODO: GIArgument(interface)[invalid] -> Ruby"); break; case GI_INFO_TYPE_FUNCTION: rb_raise(rb_eNotImpError, "TODO: GIArgument(interface)[function] -> Ruby"); break; case GI_INFO_TYPE_CALLBACK: rb_raise(rb_eNotImpError, "TODO: GIArgument(interface)[callback] -> Ruby"); break; case GI_INFO_TYPE_STRUCT: rb_interface = BOXED2RVAL(argument->v_pointer, gtype); break; case GI_INFO_TYPE_BOXED: rb_raise(rb_eNotImpError, "TODO: GIArgument(interface)[boxed] -> Ruby"); break; case GI_INFO_TYPE_ENUM: if (gtype == G_TYPE_NONE) { rb_interface = INT2NUM(argument->v_int32); } else { rb_interface = GENUM2RVAL(argument->v_int32, gtype); } break; case GI_INFO_TYPE_FLAGS: if (gtype == G_TYPE_NONE) { rb_interface = INT2NUM(argument->v_int32); } else { rb_interface = GFLAGS2RVAL(argument->v_int32, gtype); } break; case GI_INFO_TYPE_OBJECT: rb_interface = GOBJ2RVAL(argument->v_pointer); break; case GI_INFO_TYPE_INTERFACE: rb_interface = GOBJ2RVAL(argument->v_pointer); break; case GI_INFO_TYPE_CONSTANT: rb_raise(rb_eNotImpError, "TODO: GIArgument(interface)[constant] -> Ruby"); break; case GI_INFO_TYPE_INVALID_0: g_assert_not_reached(); break; case GI_INFO_TYPE_UNION: rb_interface = BOXED2RVAL(argument->v_pointer, gtype); break; case GI_INFO_TYPE_VALUE: rb_raise(rb_eNotImpError, "TODO: GIArgument(interface)[value] -> Ruby"); break; case GI_INFO_TYPE_SIGNAL: rb_raise(rb_eNotImpError, "TODO: GIArgument(interface)[signal] -> Ruby"); break; case GI_INFO_TYPE_VFUNC: rb_raise(rb_eNotImpError, "TODO: GIArgument(interface)[vfunc] -> Ruby"); break; case GI_INFO_TYPE_PROPERTY: rb_raise(rb_eNotImpError, "TODO: GIArgument(interface)[property] -> Ruby"); break; case GI_INFO_TYPE_FIELD: rb_raise(rb_eNotImpError, "TODO: GIArgument(interface)[field] -> Ruby"); break; case GI_INFO_TYPE_ARG: rb_raise(rb_eNotImpError, "TODO: GIArgument(interface)[arg] -> Ruby"); break; case GI_INFO_TYPE_TYPE: rb_raise(rb_eNotImpError, "TODO: GIArgument(interface)[type] -> Ruby"); break; case GI_INFO_TYPE_UNRESOLVED: rb_raise(rb_eNotImpError, "TODO: GIArgument(interface)[unresolved] -> Ruby"); break; default: g_assert_not_reached(); break; } g_base_info_unref(interface_info); return rb_interface; }
gint pygi_set_property_value_real (PyGObject *instance, const gchar *attr_name, PyObject *py_value) { GType g_type; GIPropertyInfo *property_info = NULL; char *property_name = g_strdup (attr_name); GITypeInfo *type_info = NULL; GITypeTag type_tag; GITransfer transfer; GValue value = { 0, }; GIArgument arg = { 0, }; GParamSpec *pspec = NULL; gint ret_value = -1; canonicalize_key (property_name); g_type = pyg_type_from_object ((PyObject *)instance); property_info = _pygi_lookup_property_from_g_type (g_type, property_name); if (property_info == NULL) goto out; pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (instance->obj), attr_name); if (pspec == NULL) goto out; if (! (pspec->flags & G_PARAM_WRITABLE)) goto out; type_info = g_property_info_get_type (property_info); transfer = g_property_info_get_ownership_transfer (property_info); arg = _pygi_argument_from_object (py_value, type_info, transfer); if (PyErr_Occurred()) goto out; g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); // FIXME: Lots of types still unhandled type_tag = g_type_info_get_tag (type_info); switch (type_tag) { case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *info; GIInfoType info_type; GType type; info = g_type_info_get_interface (type_info); type = g_registered_type_info_get_g_type (info); info_type = g_base_info_get_type (info); g_base_info_unref (info); switch (info_type) { case GI_INFO_TYPE_ENUM: g_value_set_enum (&value, arg.v_int32); break; case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: g_value_set_object (&value, arg.v_pointer); break; case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: if (g_type_is_a (type, G_TYPE_BOXED)) { g_value_set_boxed (&value, arg.v_pointer); } else { PyErr_Format (PyExc_NotImplementedError, "Setting properties of type '%s' is not implemented", g_type_name (type)); } break; default: PyErr_Format (PyExc_NotImplementedError, "Setting properties of type '%s' is not implemented", g_type_name (type)); goto out; } break; } case GI_TYPE_TAG_BOOLEAN: g_value_set_boolean (&value, arg.v_boolean); break; case GI_TYPE_TAG_INT8: g_value_set_schar (&value, arg.v_int8); break; case GI_TYPE_TAG_INT16: case GI_TYPE_TAG_INT32: if (G_VALUE_HOLDS_LONG (&value)) g_value_set_long (&value, arg.v_long); else g_value_set_int (&value, arg.v_int); break; case GI_TYPE_TAG_INT64: if (G_VALUE_HOLDS_LONG (&value)) g_value_set_long (&value, arg.v_long); else g_value_set_int64 (&value, arg.v_int64); break; case GI_TYPE_TAG_UINT8: g_value_set_uchar (&value, arg.v_uint8); break; case GI_TYPE_TAG_UINT16: case GI_TYPE_TAG_UINT32: if (G_VALUE_HOLDS_ULONG (&value)) g_value_set_ulong (&value, arg.v_ulong); else g_value_set_uint (&value, arg.v_uint); break; case GI_TYPE_TAG_UINT64: if (G_VALUE_HOLDS_ULONG (&value)) g_value_set_ulong (&value, arg.v_ulong); else g_value_set_uint64 (&value, arg.v_uint64); break; case GI_TYPE_TAG_FLOAT: g_value_set_float (&value, arg.v_float); break; case GI_TYPE_TAG_DOUBLE: g_value_set_double (&value, arg.v_double); break; case GI_TYPE_TAG_GTYPE: g_value_set_gtype (&value, arg.v_size); break; case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: g_value_set_string (&value, arg.v_string); break; case GI_TYPE_TAG_GHASH: g_value_set_boxed (&value, arg.v_pointer); break; case GI_TYPE_TAG_GLIST: g_value_set_pointer (&value, arg.v_pointer); break; case GI_TYPE_TAG_ARRAY: { GArray *arg_items = (GArray*) arg.v_pointer; gchar** strings; int i; if (arg_items == NULL) goto out; strings = g_new0 (char*, arg_items->len); for (i = 0; i < arg_items->len; ++i) { strings[i] = g_array_index (arg_items, GIArgument, i).v_string; } g_array_free (arg_items, TRUE); g_value_set_boxed (&value, strings); break; } default: PyErr_Format (PyExc_NotImplementedError, "Setting properties of type %s is not implemented", g_type_tag_to_string (g_type_info_get_tag (type_info))); goto out; } g_object_set_property (instance->obj, attr_name, &value); ret_value = 0; out: g_free (property_name); if (property_info != NULL) g_base_info_unref (property_info); if (type_info != NULL) g_base_info_unref (type_info); return ret_value; }
/* * Handle setting up the prototype and constructor for a GObject type * Namespace.Type will be the constructor and Namespace.Type.prototype is * the prototype object. Namespace.Type.type will be the GType. */ static void seed_gi_importer_handle_object(JSContextRef ctx, JSObjectRef namespace_ref, GIObjectInfo* info, JSValueRef* exception) { GType type; JSClassRef class_ref; type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*) info); if (type != 0) { GIFunctionInfo* finfo; GIFunctionInfoFlags flags; JSObjectRef constructor_ref; guint i, n_methods; class_ref = seed_gobject_get_class_for_gtype(ctx, type); constructor_ref = JSObjectMake(ctx, gobject_constructor_class, (gpointer) type); seed_object_set_property(ctx, constructor_ref, "type", seed_value_from_long(ctx, type, exception)); n_methods = g_object_info_get_n_methods(info); for (i = 0; i < n_methods; i++) { finfo = g_object_info_get_method(info, i); flags = g_function_info_get_flags(finfo); if (flags & GI_FUNCTION_IS_CONSTRUCTOR) { JSObjectRef constructor = JSObjectMake(ctx, gobject_named_constructor_class, finfo); const gchar* fname = g_base_info_get_name((GIBaseInfo*) finfo); if (g_strrstr(fname, "new_") == fname) { // To be compatible with gjs, we need to have a method with // new_, too. seed_object_set_property(ctx, constructor_ref, fname, constructor); fname += 4; } else if (!g_strcmp0(fname, "new")) { // To be compatible with gjs, we need to have new as // function, too. seed_object_set_property(ctx, constructor_ref, fname, constructor); fname = "c_new"; } seed_object_set_property(ctx, constructor_ref, fname, constructor); } else if (!(flags & GI_FUNCTION_IS_METHOD)) { seed_gobject_define_property_from_function_info(ctx, finfo, constructor_ref, FALSE); } else { g_base_info_unref((GIBaseInfo*) finfo); } } seed_object_set_property(ctx, namespace_ref, g_base_info_get_name((GIBaseInfo*) info), constructor_ref); seed_object_set_property(ctx, constructor_ref, "prototype", seed_gobject_get_prototype_for_gtype(type)); } }
JSBool gjs_define_boxed_class(JSContext *context, JSObject *in_object, GIBoxedInfo *info, JSObject **constructor_p, JSObject **prototype_p) { const char *constructor_name; JSObject *prototype; JSObject *constructor; jsval value; Boxed *priv; /* See the comment in gjs_define_object_class() for an * explanation of how this all works; Boxed is pretty much the * same as Object. */ 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, "boxed %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; } } if (!gjs_init_class_dynamic(context, in_object, NULL, /* parent prototype */ g_base_info_get_namespace( (GIBaseInfo*) info), constructor_name, &gjs_boxed_class, gjs_boxed_constructor, 1, /* props of prototype */ &gjs_boxed_proto_props[0], /* funcs of prototype */ &gjs_boxed_proto_funcs[0], /* props of constructor, MyConstructor.myprop */ NULL, /* funcs of constructor, MyConstructor.myfunc() */ NULL, &prototype, &constructor)) { gjs_log_exception(context, NULL); gjs_fatal("Can't init class %s", constructor_name); } GJS_INC_COUNTER(boxed); priv = g_slice_new0(Boxed); priv->info = info; boxed_fill_prototype_info(priv); g_base_info_ref( (GIBaseInfo*) priv->info); priv->gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo*) 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); priv->can_allocate_directly = struct_is_simple (priv->info); define_boxed_class_fields (context, priv, prototype); gjs_define_static_methods (context, constructor, priv->gtype, priv->info); value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, priv->gtype)); JS_DefineProperty(context, constructor, "$gtype", value, NULL, NULL, JSPROP_PERMANENT); if (constructor_p) *constructor_p = constructor; if (prototype_p) *prototype_p = prototype; return JS_TRUE; }
PyObject * pygi_get_property_value_real (PyGObject *instance, const gchar *attr_name) { GType g_type; GIPropertyInfo *property_info = NULL; char *property_name = g_strdup (attr_name); GParamSpec *pspec = NULL; GValue value = { 0, }; GIArgument arg = { 0, }; PyObject *py_value = NULL; GITypeInfo *type_info = NULL; GITransfer transfer; canonicalize_key (property_name); g_type = pyg_type_from_object ((PyObject *)instance); property_info = _pygi_lookup_property_from_g_type (g_type, property_name); if (property_info == NULL) goto out; pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (instance->obj), attr_name); if (pspec == NULL) goto out; g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); g_object_get_property (instance->obj, attr_name, &value); type_info = g_property_info_get_type (property_info); transfer = g_property_info_get_ownership_transfer (property_info); GITypeTag type_tag = g_type_info_get_tag (type_info); switch (type_tag) { case GI_TYPE_TAG_BOOLEAN: arg.v_boolean = g_value_get_boolean (&value); break; case GI_TYPE_TAG_INT8: arg.v_int8 = g_value_get_schar (&value); break; case GI_TYPE_TAG_INT16: case GI_TYPE_TAG_INT32: if (G_VALUE_HOLDS_LONG (&value)) arg.v_long = g_value_get_long (&value); else arg.v_int = g_value_get_int (&value); break; case GI_TYPE_TAG_INT64: if (G_VALUE_HOLDS_LONG (&value)) arg.v_long = g_value_get_long (&value); else arg.v_int64 = g_value_get_int64 (&value); break; case GI_TYPE_TAG_UINT8: arg.v_uint8 = g_value_get_uchar (&value); break; case GI_TYPE_TAG_UINT16: case GI_TYPE_TAG_UINT32: if (G_VALUE_HOLDS_ULONG (&value)) arg.v_ulong = g_value_get_ulong (&value); else arg.v_uint = g_value_get_uint (&value); break; case GI_TYPE_TAG_UINT64: if (G_VALUE_HOLDS_ULONG (&value)) arg.v_ulong = g_value_get_ulong (&value); else arg.v_uint64 = g_value_get_uint64 (&value); break; case GI_TYPE_TAG_FLOAT: arg.v_float = g_value_get_float (&value); break; case GI_TYPE_TAG_DOUBLE: arg.v_double = g_value_get_double (&value); break; case GI_TYPE_TAG_GTYPE: arg.v_size = g_value_get_gtype (&value); break; case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: arg.v_string = g_value_dup_string (&value); break; case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *info; GIInfoType info_type; GType type; info = g_type_info_get_interface (type_info); type = g_registered_type_info_get_g_type (info); info_type = g_base_info_get_type (info); g_base_info_unref (info); switch (info_type) { case GI_INFO_TYPE_ENUM: arg.v_int32 = g_value_get_enum (&value); break; case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: arg.v_pointer = g_value_get_object (&value); break; case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: if (g_type_is_a (type, G_TYPE_BOXED)) { arg.v_pointer = g_value_get_boxed (&value); } else if (g_type_is_a (type, G_TYPE_POINTER)) { arg.v_pointer = g_value_get_pointer (&value); } else { PyErr_Format (PyExc_NotImplementedError, "Retrieving properties of type '%s' is not implemented", g_type_name (type)); } break; default: PyErr_Format (PyExc_NotImplementedError, "Retrieving properties of type '%s' is not implemented", g_type_name (type)); goto out; } break; } case GI_TYPE_TAG_GHASH: arg.v_pointer = g_value_get_boxed (&value); break; case GI_TYPE_TAG_GLIST: arg.v_pointer = g_value_get_pointer (&value); break; case GI_TYPE_TAG_ARRAY: { gchar** strings; GArray *arg_items; int i; strings = g_value_get_boxed (&value); if (strings == NULL) arg.v_pointer = NULL; else { arg_items = g_array_sized_new (TRUE, TRUE, sizeof (GIArgument), g_strv_length (strings)); g_array_set_size (arg_items, g_strv_length (strings)); for (i = 0; strings[i] != NULL; ++i) { g_array_index (arg_items, GIArgument, i).v_string = strings[i]; } arg.v_pointer = arg_items; } break; } default: PyErr_Format (PyExc_NotImplementedError, "Retrieving properties of type %s is not implemented", g_type_tag_to_string (g_type_info_get_tag (type_info))); goto out; } py_value = _pygi_argument_to_object (&arg, type_info, transfer); out: g_free (property_name); if (property_info != NULL) g_base_info_unref (property_info); if (type_info != NULL) g_base_info_unref (type_info); return py_value; }
static void pygi_signal_closure_marshal(GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data) { PyGILState_STATE state; PyGClosure *pc = (PyGClosure *)closure; PyObject *params, *ret = NULL; guint i; GISignalInfo *signal_info; gint n_sig_info_args; gint sig_info_highest_arg; GSList *list_item = NULL; GSList *pass_by_ref_structs = NULL; state = PyGILState_Ensure(); signal_info = ((PyGISignalClosure *)closure)->signal_info; n_sig_info_args = g_callable_info_get_n_args(signal_info); /* the first argument to a signal callback is instance, but instance is not counted in the introspection data */ sig_info_highest_arg = n_sig_info_args + 1; g_assert_cmpint(sig_info_highest_arg, ==, n_param_values); /* construct Python tuple for the parameter values */ params = PyTuple_New(n_param_values); for (i = 0; i < n_param_values; i++) { /* swap in a different initial data for connect_object() */ if (i == 0 && G_CCLOSURE_SWAP_DATA(closure)) { g_return_if_fail(pc->swap_data != NULL); Py_INCREF(pc->swap_data); PyTuple_SetItem(params, 0, pc->swap_data); } else if (i == 0) { PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); if (!item) { goto out; } PyTuple_SetItem(params, i, item); } else if (i < sig_info_highest_arg) { GIArgInfo arg_info; GITypeInfo type_info; GITypeTag type_tag; GIArgument arg = { 0, }; PyObject *item = NULL; gboolean free_array = FALSE; gboolean pass_struct_by_ref = FALSE; g_callable_info_load_arg(signal_info, i - 1, &arg_info); g_arg_info_load_type(&arg_info, &type_info); arg = _pygi_argument_from_g_value(¶m_values[i], &type_info); type_tag = g_type_info_get_tag (&type_info); if (type_tag == GI_TYPE_TAG_ARRAY) { /* Skip the self argument of param_values */ arg.v_pointer = _pygi_argument_to_array (&arg, _pygi_argument_array_length_marshal, (void *)(param_values + 1), signal_info, &type_info, &free_array); } /* Hack to ensure struct arguments are passed-by-reference allowing * callback implementors to modify the struct values. This is needed * for keeping backwards compatibility and should be removed in future * versions which support signal output arguments as return values. * See: https://bugzilla.gnome.org/show_bug.cgi?id=735486 * * Note the logic here must match the logic path taken in _pygi_argument_to_object. */ if (type_tag == GI_TYPE_TAG_INTERFACE) { GIBaseInfo *info = g_type_info_get_interface (&type_info); GIInfoType info_type = g_base_info_get_type (info); if (info_type == GI_INFO_TYPE_STRUCT || info_type == GI_INFO_TYPE_BOXED || info_type == GI_INFO_TYPE_UNION) { GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info); gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) && (g_struct_info_is_foreign ((GIStructInfo *) info)); if (!is_foreign && !g_type_is_a (gtype, G_TYPE_VALUE) && g_type_is_a (gtype, G_TYPE_BOXED)) { pass_struct_by_ref = TRUE; } } g_base_info_unref (info); } if (pass_struct_by_ref) { /* transfer everything will ensure the struct is not copied when wrapped. */ item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_EVERYTHING); if (item && PyObject_IsInstance (item, (PyObject *) &PyGIBoxed_Type)) { ((PyGBoxed *)item)->free_on_dealloc = FALSE; pass_by_ref_structs = g_slist_prepend (pass_by_ref_structs, item); } } else { item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_NOTHING); } if (free_array) { g_array_free (arg.v_pointer, FALSE); } if (item == NULL) { PyErr_Print (); goto out; } PyTuple_SetItem(params, i, item); } } /* params passed to function may have extra arguments */ if (pc->extra_args) { PyObject *tuple = params; params = PySequence_Concat(tuple, pc->extra_args); Py_DECREF(tuple); } ret = PyObject_CallObject(pc->callback, params); if (ret == NULL) { if (pc->exception_handler) pc->exception_handler(return_value, n_param_values, param_values); else PyErr_Print(); goto out; } if (G_IS_VALUE(return_value) && pyg_value_from_pyobject(return_value, ret) != 0) { PyErr_SetString(PyExc_TypeError, "can't convert return value to desired type"); if (pc->exception_handler) pc->exception_handler(return_value, n_param_values, param_values); else PyErr_Print(); } Py_DECREF(ret); /* Run through the list of structs which have been passed by reference and * check if they are being held longer than the duration of the callback * execution. This is determined if the ref count is greater than 1. * A single ref is held by the argument list and any more would mean the callback * stored a ref somewhere else. In this case we make an internal copy of * the boxed struct so Python can own the memory to it. */ list_item = pass_by_ref_structs; while (list_item) { PyObject *item = list_item->data; if (item->ob_refcnt > 1) { _pygi_boxed_copy_in_place ((PyGIBoxed *)item); } list_item = g_slist_next (list_item); } out: g_slist_free (pass_by_ref_structs); Py_DECREF(params); PyGILState_Release(state); }
/* * Like JSResolveOp, but flags provide contextual information as follows: * * JSRESOLVE_QUALIFIED a qualified property id: obj.id or obj[id], not id * JSRESOLVE_ASSIGNING obj[id] is on the left-hand side of an assignment * JSRESOLVE_DETECTING 'if (o.p)...' or similar detection opcode sequence * JSRESOLVE_DECLARING var, const, or boxed prolog declaration opcode * JSRESOLVE_CLASSNAME class name used when constructing * * The *objp out parameter, on success, should be null to indicate that id * was not resolved; and non-null, referring to obj or one of its prototypes, * if id was resolved. */ static JSBool union_new_resolve(JSContext *context, JSObject **obj, jsid *id, unsigned flags, JSObject **objp) { Union *priv; char *name; JSBool ret = JS_TRUE; *objp = NULL; if (!gjs_get_string_id(context, *id, &name)) return JS_TRUE; /* not resolved, but no error */ priv = priv_from_js(context, *obj); gjs_debug_jsprop(GJS_DEBUG_GBOXED, "Resolve prop '%s' hook obj %p priv %p", name, *obj, priv); if (priv == NULL) { ret = JS_FALSE; /* wrong class */ goto out; } if (priv->gboxed == NULL) { /* We are the prototype, so look for methods and other class properties */ GIFunctionInfo *method_info; method_info = g_union_info_find_method((GIUnionInfo*) priv->info, name); if (method_info != NULL) { JSObject *union_proto; const char *method_name; #if GJS_VERBOSE_ENABLE_GI_USAGE _gjs_log_info_usage((GIBaseInfo*) method_info); #endif method_name = g_base_info_get_name( (GIBaseInfo*) method_info); gjs_debug(GJS_DEBUG_GBOXED, "Defining method %s in prototype for %s.%s", method_name, g_base_info_get_namespace( (GIBaseInfo*) priv->info), g_base_info_get_name( (GIBaseInfo*) priv->info)); union_proto = *obj; if (gjs_define_function(context, union_proto, g_registered_type_info_get_g_type(priv->info), method_info) == NULL) { g_base_info_unref( (GIBaseInfo*) method_info); ret = JS_FALSE; goto out; } *objp = union_proto; /* we defined the prop in object_proto */ g_base_info_unref( (GIBaseInfo*) method_info); } } else { /* We are an instance, not a prototype, so look for * per-instance props that we want to define on the * JSObject. Generally we do not want to cache these in JS, we * want to always pull them from the C object, or JS would not * see any changes made from C. So we use the get/set prop * hooks, not this resolve hook. */ } out: g_free(name); return ret; }
/** * _pygi_argument_to_object: * @arg: The argument to convert to an object. * @type_info: Type info for @arg * @transfer: * * If the argument is of type array, it must be encoded in a GArray, by calling * _pygi_argument_to_array(). This logic can not be folded into this method * as determining array lengths may require access to method call arguments. * * Returns: A PyObject representing @arg */ PyObject * _pygi_argument_to_object (GIArgument *arg, GITypeInfo *type_info, GITransfer transfer) { GITypeTag type_tag; PyObject *object = NULL; type_tag = g_type_info_get_tag (type_info); object = _pygi_marshal_to_py_basic_type (arg, type_tag, transfer); if (object) return object; switch (type_tag) { case GI_TYPE_TAG_VOID: { if (g_type_info_is_pointer (type_info)) { g_warn_if_fail (transfer == GI_TRANSFER_NOTHING); object = PyLong_FromVoidPtr (arg->v_pointer); } break; } case GI_TYPE_TAG_ARRAY: { /* Arrays are assumed to be packed in a GArray */ GArray *array; GITypeInfo *item_type_info; GITypeTag item_type_tag; GITransfer item_transfer; gsize i, item_size; if (arg->v_pointer == NULL) return PyList_New (0); item_type_info = g_type_info_get_param_type (type_info, 0); g_assert (item_type_info != NULL); item_type_tag = g_type_info_get_tag (item_type_info); item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; array = arg->v_pointer; item_size = g_array_get_element_size (array); if (G_UNLIKELY (item_size > sizeof(GIArgument))) { g_critical ("Stack overflow protection. " "Can't copy array element into GIArgument."); return PyList_New (0); } if (item_type_tag == GI_TYPE_TAG_UINT8) { /* Return as a byte array */ object = PYGLIB_PyBytes_FromStringAndSize (array->data, array->len); } else { object = PyList_New (array->len); if (object == NULL) { g_critical ("Failure to allocate array for %u items", array->len); g_base_info_unref ( (GIBaseInfo *) item_type_info); break; } for (i = 0; i < array->len; i++) { GIArgument item = { 0 }; PyObject *py_item; memcpy (&item, array->data + i * item_size, item_size); py_item = _pygi_argument_to_object (&item, item_type_info, item_transfer); if (py_item == NULL) { Py_CLEAR (object); _PyGI_ERROR_PREFIX ("Item %zu: ", i); break; } PyList_SET_ITEM (object, i, py_item); } } g_base_info_unref ( (GIBaseInfo *) item_type_info); break; } case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *info; GIInfoType info_type; info = g_type_info_get_interface (type_info); info_type = g_base_info_get_type (info); switch (info_type) { case GI_INFO_TYPE_CALLBACK: { g_assert_not_reached(); } case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: { PyObject *py_type; GType g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) && (g_struct_info_is_foreign ((GIStructInfo *) info)); /* Special case variant and none to force loading from py module. */ if (g_type == G_TYPE_VARIANT || g_type == G_TYPE_NONE) { py_type = _pygi_type_import_by_gi_info (info); } else { py_type = _pygi_type_get_from_g_type (g_type); } object = pygi_arg_struct_to_py_marshal (arg, info, /*interface_info*/ g_type, py_type, transfer, FALSE, /*is_allocated*/ is_foreign); Py_XDECREF (py_type); break; } case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: { GType type; type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); if (type == G_TYPE_NONE) { /* An enum with a GType of None is an enum without GType */ PyObject *py_type = _pygi_type_import_by_gi_info (info); PyObject *py_args = NULL; if (!py_type) return NULL; py_args = PyTuple_New (1); if (PyTuple_SetItem (py_args, 0, PyLong_FromLong (arg->v_int)) != 0) { Py_DECREF (py_args); Py_DECREF (py_type); return NULL; } object = PyObject_CallFunction (py_type, "i", arg->v_int); Py_DECREF (py_args); Py_DECREF (py_type); } else if (info_type == GI_INFO_TYPE_ENUM) { object = pyg_enum_from_gtype (type, arg->v_int); } else { object = pyg_flags_from_gtype (type, arg->v_uint); } break; } case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: object = pygi_arg_gobject_to_py_called_from_c (arg, transfer); break; default: g_assert_not_reached(); } g_base_info_unref (info); break; } case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: { GSList *list; gsize length; GITypeInfo *item_type_info; GITransfer item_transfer; gsize i; list = arg->v_pointer; length = g_slist_length (list); object = PyList_New (length); if (object == NULL) { break; } item_type_info = g_type_info_get_param_type (type_info, 0); g_assert (item_type_info != NULL); item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; for (i = 0; list != NULL; list = g_slist_next (list), i++) { GIArgument item; PyObject *py_item; item.v_pointer = list->data; py_item = _pygi_argument_to_object (&item, item_type_info, item_transfer); if (py_item == NULL) { Py_CLEAR (object); _PyGI_ERROR_PREFIX ("Item %zu: ", i); break; } PyList_SET_ITEM (object, i, py_item); } g_base_info_unref ( (GIBaseInfo *) item_type_info); break; } case GI_TYPE_TAG_GHASH: { GITypeInfo *key_type_info; GITypeInfo *value_type_info; GITransfer item_transfer; GHashTableIter hash_table_iter; GIArgument key; GIArgument value; if (arg->v_pointer == NULL) { object = Py_None; Py_INCREF (object); break; } object = PyDict_New(); if (object == NULL) { break; } key_type_info = g_type_info_get_param_type (type_info, 0); g_assert (key_type_info != NULL); g_assert (g_type_info_get_tag (key_type_info) != GI_TYPE_TAG_VOID); value_type_info = g_type_info_get_param_type (type_info, 1); g_assert (value_type_info != NULL); g_assert (g_type_info_get_tag (value_type_info) != GI_TYPE_TAG_VOID); item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; g_hash_table_iter_init (&hash_table_iter, (GHashTable *) arg->v_pointer); while (g_hash_table_iter_next (&hash_table_iter, &key.v_pointer, &value.v_pointer)) { PyObject *py_key; PyObject *py_value; int retval; py_key = _pygi_argument_to_object (&key, key_type_info, item_transfer); if (py_key == NULL) { break; } _pygi_hash_pointer_to_arg (&value, g_type_info_get_tag (value_type_info)); py_value = _pygi_argument_to_object (&value, value_type_info, item_transfer); if (py_value == NULL) { Py_DECREF (py_key); break; } retval = PyDict_SetItem (object, py_key, py_value); Py_DECREF (py_key); Py_DECREF (py_value); if (retval < 0) { Py_CLEAR (object); break; } } g_base_info_unref ( (GIBaseInfo *) key_type_info); g_base_info_unref ( (GIBaseInfo *) value_type_info); break; } case GI_TYPE_TAG_ERROR: { GError *error = (GError *) arg->v_pointer; if (error != NULL && transfer == GI_TRANSFER_NOTHING) { /* If we have not been transferred the ownership we must copy * the error, because pygi_error_check() is going to free it. */ error = g_error_copy (error); } if (pygi_error_check (&error)) { PyObject *err_type; PyObject *err_value; PyObject *err_trace; PyErr_Fetch (&err_type, &err_value, &err_trace); Py_XDECREF (err_type); Py_XDECREF (err_trace); object = err_value; } else { object = Py_None; Py_INCREF (object); break; } break; } default: { g_assert_not_reached(); } } return object; }
void gy_value_init(GValue * val, GITypeInfo * info) { GY_DEBUG("in gy_value_init\n"); GITypeTag type = g_type_info_get_tag(info); GIBaseInfo * itrf; GY_DEBUG("Initializing GValue to %s\n", g_type_tag_to_string(type)); switch (type) { /* basic types */ case GI_TYPE_TAG_BOOLEAN: g_value_init(val, G_TYPE_BOOLEAN); break; case GI_TYPE_TAG_INT8: g_value_init(val, G_TYPE_CHAR); break; case GI_TYPE_TAG_UINT8: g_value_init(val, G_TYPE_UCHAR); break; case GI_TYPE_TAG_INT16: case GI_TYPE_TAG_INT32: g_value_init(val, G_TYPE_INT); break; case GI_TYPE_TAG_UINT16: case GI_TYPE_TAG_UINT32: g_value_init(val, G_TYPE_INT); break; case GI_TYPE_TAG_INT64: g_value_init(val, G_TYPE_INT64); break; case GI_TYPE_TAG_UINT64: g_value_init(val, G_TYPE_UINT64); break; case GI_TYPE_TAG_FLOAT: g_value_init(val, G_TYPE_FLOAT); break; case GI_TYPE_TAG_DOUBLE: g_value_init(val, G_TYPE_DOUBLE); break; case GI_TYPE_TAG_GTYPE: g_value_init(val, G_TYPE_GTYPE); break; case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: g_value_init(val, G_TYPE_STRING); GY_DEBUG("GValue is string\n"); break; /* interface types */ case GI_TYPE_TAG_INTERFACE: itrf = g_type_info_get_interface(info); switch(g_base_info_get_type (itrf)) { case GI_INFO_TYPE_OBJECT: g_value_init(val, G_TYPE_OBJECT); break; case GI_INFO_TYPE_ENUM: g_value_init(val, g_registered_type_info_get_g_type(itrf)); GY_DEBUG("GValue is enum\n"); break; default: y_errorn("Unimplemented GValue interface type %ld", g_base_info_get_type (itrf)); } g_base_info_unref(itrf); break; case GI_TYPE_TAG_VOID: default: y_error("Unimplement property GValue type"); } GY_DEBUG("out gy_value_init\n"); }
static void rb_gi_argument_from_ruby_interface(GIArgument *argument, GITypeInfo *type_info, VALUE rb_argument) { GIBaseInfo *interface_info; GIInfoType interface_type; GType gtype; interface_info = g_type_info_get_interface(type_info); interface_type = g_base_info_get_type(interface_info); gtype = g_registered_type_info_get_g_type(interface_info); switch (interface_type) { case GI_INFO_TYPE_INVALID: case GI_INFO_TYPE_FUNCTION: case GI_INFO_TYPE_CALLBACK: rb_raise(rb_eNotImpError, "TODO: Ruby -> GIArgument(interface)[%s]: <%s>", g_info_type_to_string(interface_type), g_base_info_get_name(interface_info)); break; case GI_INFO_TYPE_STRUCT: if (gtype == G_TYPE_VALUE) { GValue *gvalue; gvalue = ALLOC(GValue); memset(gvalue, 0, sizeof(GValue)); if (rb_obj_is_kind_of(rb_argument, rb_cGLibValue)) { GValue *source_gvalue; source_gvalue = RVAL2BOXED(rb_argument, G_TYPE_VALUE); g_value_init(gvalue, source_gvalue->g_type); g_value_copy(source_gvalue, gvalue); } else { rbgobj_initialize_gvalue(gvalue, rb_argument); } argument->v_pointer = gvalue; } else { argument->v_pointer = RVAL2BOXED(rb_argument, gtype); } break; case GI_INFO_TYPE_BOXED: rb_raise(rb_eNotImpError, "TODO: Ruby -> GIArgument(interface)[%s]: <%s>", g_info_type_to_string(interface_type), g_base_info_get_name(interface_info)); break; case GI_INFO_TYPE_ENUM: if (gtype == G_TYPE_NONE) { argument->v_int32 = NUM2INT(rb_argument); } else { argument->v_int32 = RVAL2GENUM(rb_argument, gtype); } break; case GI_INFO_TYPE_FLAGS: if (gtype == G_TYPE_NONE) { argument->v_int32 = NUM2INT(rb_argument); } else { argument->v_int32 = RVAL2GFLAGS(rb_argument, gtype); } break; case GI_INFO_TYPE_OBJECT: case GI_INFO_TYPE_INTERFACE: argument->v_pointer = RVAL2GOBJ(rb_argument); break; case GI_INFO_TYPE_CONSTANT: rb_raise(rb_eNotImpError, "TODO: Ruby -> GIArgument(interface)[%s]: <%s>", g_info_type_to_string(interface_type), g_base_info_get_name(interface_info)); break; case GI_INFO_TYPE_INVALID_0: g_assert_not_reached(); break; case GI_INFO_TYPE_UNION: case GI_INFO_TYPE_VALUE: case GI_INFO_TYPE_SIGNAL: case GI_INFO_TYPE_VFUNC: case GI_INFO_TYPE_PROPERTY: case GI_INFO_TYPE_FIELD: case GI_INFO_TYPE_ARG: case GI_INFO_TYPE_TYPE: case GI_INFO_TYPE_UNRESOLVED: default: rb_raise(rb_eNotImpError, "TODO: Ruby -> GIArgument(interface)[%s]: <%s>", g_info_type_to_string(interface_type), g_base_info_get_name(interface_info)); break; } g_base_info_unref(interface_info); }
JSBool gjs_define_interface_class(JSContext *context, JSObject *in_object, GIInterfaceInfo *info, JSObject **prototype_p) { Interface *priv; const char *constructor_name; JSObject *constructor; JSObject *prototype; jsval value; constructor_name = g_base_info_get_name((GIBaseInfo*)info); gjs_object_get_property(context, in_object, constructor_name, &value); if (!JSVAL_IS_VOID(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, "prototype property does not appear to exist or has wrong type"); return JS_FALSE; } else { if (prototype_p) *prototype_p = JSVAL_TO_OBJECT(value); return JS_TRUE; } return JS_TRUE; } if (!gjs_init_class_dynamic(context, in_object, NULL, g_base_info_get_namespace((GIBaseInfo*)info), constructor_name, &gjs_interface_class, gjs_interface_constructor, 0, /* props of prototype */ &gjs_interface_proto_props[0], /* funcs of prototype */ &gjs_interface_proto_funcs[0], /* props of constructor, MyConstructor.myprop */ NULL, /* funcs of constructor, MyConstructor.myfunc() */ NULL, &prototype, &constructor)) { gjs_fatal("Can't init class %s", constructor_name); } GJS_INC_COUNTER(interface); priv = g_slice_new0(Interface); priv->info = info; priv->gtype = g_registered_type_info_get_g_type(priv->info); g_base_info_ref((GIBaseInfo*)priv->info); JS_SetPrivate(context, prototype, priv); gjs_define_static_methods(context, constructor, priv->gtype, priv->info); value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, priv->gtype)); JS_DefineProperty(context, constructor, "$gtype", value, NULL, NULL, JSPROP_PERMANENT); if (prototype_p) *prototype_p = prototype; return JS_TRUE; }
/* Marshalls single value from Lua to GLib/C. */ int lgi_marshal_2c (lua_State *L, GITypeInfo *ti, GIArgInfo *ai, GITransfer transfer, gpointer target, int narg, int parent, GICallableInfo *ci, void **args) { int nret = 0; gboolean optional = (parent == LGI_PARENT_CALLER_ALLOC) || (ai == NULL || (g_arg_info_is_optional (ai) || g_arg_info_may_be_null (ai))); GITypeTag tag = g_type_info_get_tag (ti); GIArgument *arg = target; /* Convert narg stack position to absolute one, because during marshalling some temporary items might be pushed to the stack, which would disrupt relative stack addressing of the value. */ lgi_makeabs(L, narg); switch (tag) { case GI_TYPE_TAG_BOOLEAN: { gboolean result; result = lua_toboolean (L, narg) ? TRUE : FALSE; if (parent == LGI_PARENT_FORCE_POINTER) arg->v_pointer = GINT_TO_POINTER (result); else if (parent == LGI_PARENT_IS_RETVAL) { ReturnUnion *ru = (ReturnUnion *) arg; ru->s = result; } else arg->v_boolean = result; break; } case GI_TYPE_TAG_FLOAT: case GI_TYPE_TAG_DOUBLE: { /* Retrieve number from given position. */ lua_Number num = (optional && lua_isnoneornil (L, narg)) ? 0 : luaL_checknumber (L, narg); /* Marshalling float/double into pointer target is not possible. */ g_return_val_if_fail (parent != LGI_PARENT_FORCE_POINTER, 0); /* Store read value into chosen target. */ if (tag == GI_TYPE_TAG_FLOAT) arg->v_float = (float) num; else arg->v_double = (double) num; break; } case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: { gchar *str = NULL; int type = lua_type (L, narg); if (type == LUA_TLIGHTUSERDATA) str = lua_touserdata (L, narg); else if (!optional || (type != LUA_TNIL && type != LUA_TNONE)) { if (type == LUA_TUSERDATA) str = (gchar *) lgi_udata_test (L, narg, LGI_BYTES_BUFFER); if (str == NULL) str = (gchar *) luaL_checkstring (L, narg); } if (tag == GI_TYPE_TAG_FILENAME) { /* Convert from UTF-8 to filename encoding. */ if (str) { str = g_filename_from_utf8 (str, -1, NULL, NULL, NULL); if (transfer != GI_TRANSFER_EVERYTHING) { /* Create temporary object on the stack which will destroy the allocated temporary filename. */ *lgi_guard_create (L, g_free) = (gpointer) str; nret = 1; } } } else if (transfer == GI_TRANSFER_EVERYTHING) str = g_strdup (str); if (parent == LGI_PARENT_FORCE_POINTER) arg->v_pointer = str; else arg->v_string = str; } break; case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *info = g_type_info_get_interface (ti); GIInfoType type = g_base_info_get_type (info); int info_guard; lgi_gi_info_new (L, info); info_guard = lua_gettop (L); switch (type) { case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: /* If the argument is not numeric, convert to number first. Use enum/flags 'constructor' to do this. */ if (lua_type (L, narg) != LUA_TNUMBER) { lgi_type_get_repotype (L, G_TYPE_INVALID, info); lua_pushvalue (L, narg); lua_call (L, 1, 1); narg = -1; } /* Directly store underlying value. */ marshal_2c_int (L, g_enum_info_get_storage_type (info), arg, narg, optional, parent); /* Remove the temporary value, to keep stack balanced. */ if (narg == -1) lua_pop (L, 1); break; case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: { /* Ideally the g_type_info_is_pointer() should be sufficient here, but there is some gobject-introspection quirk that some struct arguments might not be marked as pointers (e.g. g_variant_equals(), which has ctype of gconstpointer, and thus logic in girparser.c which sets is_pointer attribute fails). Workaround it by checking also argument type - structs as C function arguments are always passed as pointers. */ gboolean by_value = parent != LGI_PARENT_FORCE_POINTER && ((!g_type_info_is_pointer (ti) && ai == NULL) || parent == LGI_PARENT_CALLER_ALLOC); lgi_type_get_repotype (L, G_TYPE_INVALID, info); lgi_record_2c (L, narg, target, by_value, transfer != GI_TRANSFER_NOTHING, optional, FALSE); break; } case GI_INFO_TYPE_OBJECT: case GI_INFO_TYPE_INTERFACE: { arg->v_pointer = lgi_object_2c (L, narg, g_registered_type_info_get_g_type (info), optional, FALSE, transfer != GI_TRANSFER_NOTHING); break; } case GI_INFO_TYPE_CALLBACK: nret = marshal_2c_callable (L, info, ai, &arg->v_pointer, narg, optional, ci, args); break; default: g_assert_not_reached (); } lua_remove (L, info_guard); } break; case GI_TYPE_TAG_ARRAY: { gssize size; GIArrayType atype = g_type_info_get_array_type (ti); nret = marshal_2c_array (L, ti, atype, &arg->v_pointer, &size, narg, optional, transfer); /* Fill in array length argument, if it is specified. */ if (atype == GI_ARRAY_TYPE_C) array_get_or_set_length (ti, NULL, size, ci, args); break; } case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: nret = marshal_2c_list (L, ti, tag, &arg->v_pointer, narg, transfer); break; case GI_TYPE_TAG_GHASH: nret = marshal_2c_hash (L, ti, (GHashTable **) &arg->v_pointer, narg, optional, transfer); break; case GI_TYPE_TAG_VOID: if (g_type_info_is_pointer (ti)) { /* Check and marshal according to real Lua type. */ if (lua_isnoneornil (L, narg)) /* nil -> NULL. */ arg->v_pointer = NULL; if (lua_type (L, narg) == LUA_TSTRING) /* Use string directly. */ arg->v_pointer = (gpointer) lua_tostring (L, narg); else { int type = lua_type (L, narg); if (type == LUA_TLIGHTUSERDATA) /* Generic pointer. */ arg->v_pointer = lua_touserdata (L, narg); else { /* Check memory buffer. */ arg->v_pointer = lgi_udata_test (L, narg, LGI_BYTES_BUFFER); if (!arg->v_pointer) { /* Check object. */ arg->v_pointer = lgi_object_2c (L, narg, G_TYPE_INVALID, FALSE, TRUE, FALSE); if (!arg->v_pointer) { /* Check any kind of record. */ lua_pushnil (L); lgi_record_2c (L, narg, &arg->v_pointer, FALSE, FALSE, FALSE, TRUE); } } } } } break; default: marshal_2c_int (L, tag, arg, narg, optional, parent); } return nret; }
JSBool gjs_define_fundamental_class(JSContext *context, JSObject *in_object, GIObjectInfo *info, JSObject **constructor_p, JSObject **prototype_p) { const char *constructor_name; JSObject *prototype; jsval value; jsid js_constructor_name = JSID_VOID; JSObject *parent_proto; Fundamental *priv; JSObject *constructor; GType parent_gtype; GType gtype; GIFunctionInfo *constructor_info; /* See the comment in gjs_define_object_class() for an explanation * of how this all works; Fundamental is pretty much the same as * Object. */ constructor_name = g_base_info_get_name((GIBaseInfo *) info); constructor_info = find_fundamental_constructor(context, info, &js_constructor_name); gtype = g_registered_type_info_get_g_type (info); parent_gtype = g_type_parent(gtype); parent_proto = NULL; if (parent_gtype != G_TYPE_INVALID) parent_proto = gjs_lookup_fundamental_prototype_from_gtype(context, parent_gtype); if (!gjs_init_class_dynamic(context, in_object, /* parent prototype JSObject* for * prototype; NULL for * Object.prototype */ parent_proto, g_base_info_get_namespace((GIBaseInfo *) info), constructor_name, &gjs_fundamental_instance_class, gjs_fundamental_instance_constructor, /* number of constructor args (less can be passed) */ constructor_info != NULL ? g_callable_info_get_n_args((GICallableInfo *) constructor_info) : 0, /* props of prototype */ parent_proto ? NULL : &gjs_fundamental_instance_proto_props[0], /* funcs of prototype */ parent_proto ? NULL : &gjs_fundamental_instance_proto_funcs[0], /* props of constructor, MyConstructor.myprop */ NULL, /* funcs of constructor, MyConstructor.myfunc() */ NULL, &prototype, &constructor)) { gjs_log_exception(context); g_error("Can't init class %s", constructor_name); } /* Put the info in the prototype */ priv = g_slice_new0(Fundamental); g_assert(priv != NULL); g_assert(priv->info == NULL); priv->info = g_base_info_ref((GIBaseInfo *) info); priv->gtype = gtype; priv->constructor_name = js_constructor_name; priv->constructor_info = constructor_info; priv->ref_function = g_object_info_get_ref_function_pointer(info); g_assert(priv->ref_function != NULL); priv->unref_function = g_object_info_get_unref_function_pointer(info); g_assert(priv->unref_function != NULL); priv->set_value_function = g_object_info_get_set_value_function_pointer(info); g_assert(priv->set_value_function != NULL); priv->get_value_function = g_object_info_get_get_value_function_pointer(info); g_assert(priv->get_value_function != NULL); JS_SetPrivate(prototype, priv); gjs_debug(GJS_DEBUG_GFUNDAMENTAL, "Defined class %s prototype is %p class %p in object %p constructor %s.%s.%s", constructor_name, prototype, JS_GetClass(prototype), in_object, constructor_info != NULL ? g_base_info_get_namespace(constructor_info) : "unknown", constructor_info != NULL ? g_base_info_get_name(g_base_info_get_container(constructor_info)) : "unknown", constructor_info != NULL ? g_base_info_get_name(constructor_info) : "unknown"); if (g_object_info_get_n_fields(priv->info) > 0) { gjs_debug(GJS_DEBUG_GFUNDAMENTAL, "Fundamental type '%s.%s' apparently has accessible fields. " "Gjs has no support for this yet, ignoring these.", g_base_info_get_namespace((GIBaseInfo *)priv->info), g_base_info_get_name ((GIBaseInfo *)priv->info)); } gjs_object_define_static_methods(context, constructor, gtype, info); value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, gtype)); JS_DefineProperty(context, constructor, "$gtype", value, NULL, NULL, JSPROP_PERMANENT); if (constructor_p) *constructor_p = constructor; if (prototype_p) *prototype_p = prototype; return JS_TRUE; }
GIArgument _pygi_argument_from_object (PyObject *object, GITypeInfo *type_info, GITransfer transfer) { GIArgument arg; GITypeTag type_tag; gpointer cleanup_data = NULL; memset(&arg, 0, sizeof(GIArgument)); type_tag = g_type_info_get_tag (type_info); /* Ignores cleanup data for now. */ if (_pygi_marshal_from_py_basic_type (object, &arg, type_tag, transfer, &cleanup_data) || PyErr_Occurred()) { return arg; } switch (type_tag) { case GI_TYPE_TAG_ARRAY: { Py_ssize_t length; gboolean is_zero_terminated; GITypeInfo *item_type_info; gsize item_size; GArray *array; GITransfer item_transfer; Py_ssize_t i; if (object == Py_None) { arg.v_pointer = NULL; break; } /* Note, strings are sequences, but we cannot accept them here */ if (!PySequence_Check (object) || #if PY_VERSION_HEX < 0x03000000 PyString_Check (object) || #endif PyUnicode_Check (object)) { PyErr_SetString (PyExc_TypeError, "expected sequence"); break; } length = PySequence_Length (object); if (length < 0) { break; } is_zero_terminated = g_type_info_is_zero_terminated (type_info); item_type_info = g_type_info_get_param_type (type_info, 0); /* we handle arrays that are really strings specially, see below */ if (g_type_info_get_tag (item_type_info) == GI_TYPE_TAG_UINT8) item_size = 1; else item_size = sizeof (GIArgument); array = g_array_sized_new (is_zero_terminated, FALSE, item_size, length); if (array == NULL) { g_base_info_unref ( (GIBaseInfo *) item_type_info); PyErr_NoMemory(); break; } if (g_type_info_get_tag (item_type_info) == GI_TYPE_TAG_UINT8 && PYGLIB_PyBytes_Check(object)) { memcpy(array->data, PYGLIB_PyBytes_AsString(object), length); array->len = length; goto array_success; } item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; for (i = 0; i < length; i++) { PyObject *py_item; GIArgument item; py_item = PySequence_GetItem (object, i); if (py_item == NULL) { goto array_item_error; } item = _pygi_argument_from_object (py_item, item_type_info, item_transfer); Py_DECREF (py_item); if (PyErr_Occurred()) { goto array_item_error; } g_array_insert_val (array, i, item); continue; array_item_error: /* Free everything we have converted so far. */ _pygi_argument_release ( (GIArgument *) &array, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); array = NULL; _PyGI_ERROR_PREFIX ("Item %zd: ", i); break; } array_success: arg.v_pointer = array; g_base_info_unref ( (GIBaseInfo *) item_type_info); break; } case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *info; GIInfoType info_type; info = g_type_info_get_interface (type_info); info_type = g_base_info_get_type (info); switch (info_type) { case GI_INFO_TYPE_CALLBACK: /* This should be handled in invoke() */ g_assert_not_reached(); break; case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: { GType g_type; PyObject *py_type; gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) && (g_struct_info_is_foreign ((GIStructInfo *) info)); g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) info); /* Note for G_TYPE_VALUE g_type: * This will currently leak the GValue that is allocated and * stashed in arg.v_pointer. Out argument marshaling for caller * allocated GValues already pass in memory for the GValue. * Further re-factoring is needed to fix this leak. * See: https://bugzilla.gnome.org/show_bug.cgi?id=693405 */ pygi_arg_struct_from_py_marshal (object, &arg, NULL, /*arg_name*/ info, /*interface_info*/ g_type, py_type, transfer, FALSE, /*copy_reference*/ is_foreign, g_type_info_is_pointer (type_info)); Py_DECREF (py_type); break; } case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: { PyObject *int_; int_ = PYGLIB_PyNumber_Long (object); if (int_ == NULL) { break; } arg.v_int = PYGLIB_PyLong_AsLong (int_); Py_DECREF (int_); break; } case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: /* An error within this call will result in a NULL arg */ pygi_arg_gobject_out_arg_from_py (object, &arg, transfer); break; default: g_assert_not_reached(); } g_base_info_unref (info); break; } case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: { Py_ssize_t length; GITypeInfo *item_type_info; GSList *list = NULL; GITransfer item_transfer; Py_ssize_t i; if (object == Py_None) { arg.v_pointer = NULL; break; } length = PySequence_Length (object); if (length < 0) { break; } item_type_info = g_type_info_get_param_type (type_info, 0); g_assert (item_type_info != NULL); item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; for (i = length - 1; i >= 0; i--) { PyObject *py_item; GIArgument item; py_item = PySequence_GetItem (object, i); if (py_item == NULL) { goto list_item_error; } item = _pygi_argument_from_object (py_item, item_type_info, item_transfer); Py_DECREF (py_item); if (PyErr_Occurred()) { goto list_item_error; } if (type_tag == GI_TYPE_TAG_GLIST) { list = (GSList *) g_list_prepend ( (GList *) list, item.v_pointer); } else { list = g_slist_prepend (list, item.v_pointer); } continue; list_item_error: /* Free everything we have converted so far. */ _pygi_argument_release ( (GIArgument *) &list, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); list = NULL; _PyGI_ERROR_PREFIX ("Item %zd: ", i); break; } arg.v_pointer = list; g_base_info_unref ( (GIBaseInfo *) item_type_info); break; } case GI_TYPE_TAG_GHASH: { Py_ssize_t length; PyObject *keys; PyObject *values; GITypeInfo *key_type_info; GITypeInfo *value_type_info; GITypeTag key_type_tag; GHashFunc hash_func; GEqualFunc equal_func; GHashTable *hash_table; GITransfer item_transfer; Py_ssize_t i; if (object == Py_None) { arg.v_pointer = NULL; break; } length = PyMapping_Length (object); if (length < 0) { break; } keys = PyMapping_Keys (object); if (keys == NULL) { break; } values = PyMapping_Values (object); if (values == NULL) { Py_DECREF (keys); break; } key_type_info = g_type_info_get_param_type (type_info, 0); g_assert (key_type_info != NULL); value_type_info = g_type_info_get_param_type (type_info, 1); g_assert (value_type_info != NULL); key_type_tag = g_type_info_get_tag (key_type_info); switch (key_type_tag) { case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: hash_func = g_str_hash; equal_func = g_str_equal; break; default: hash_func = NULL; equal_func = NULL; } hash_table = g_hash_table_new (hash_func, equal_func); if (hash_table == NULL) { PyErr_NoMemory(); goto hash_table_release; } item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; for (i = 0; i < length; i++) { PyObject *py_key; PyObject *py_value; GIArgument key; GIArgument value; py_key = PyList_GET_ITEM (keys, i); py_value = PyList_GET_ITEM (values, i); key = _pygi_argument_from_object (py_key, key_type_info, item_transfer); if (PyErr_Occurred()) { goto hash_table_item_error; } value = _pygi_argument_from_object (py_value, value_type_info, item_transfer); if (PyErr_Occurred()) { _pygi_argument_release (&key, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); goto hash_table_item_error; } g_hash_table_insert (hash_table, key.v_pointer, _pygi_arg_to_hash_pointer (&value, g_type_info_get_tag (value_type_info))); continue; hash_table_item_error: /* Free everything we have converted so far. */ _pygi_argument_release ( (GIArgument *) &hash_table, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); hash_table = NULL; _PyGI_ERROR_PREFIX ("Item %zd: ", i); break; } arg.v_pointer = hash_table; hash_table_release: g_base_info_unref ( (GIBaseInfo *) key_type_info); g_base_info_unref ( (GIBaseInfo *) value_type_info); Py_DECREF (keys); Py_DECREF (values); break; } case GI_TYPE_TAG_ERROR: PyErr_SetString (PyExc_NotImplementedError, "error marshalling is not supported yet"); /* TODO */ break; default: g_assert_not_reached (); } return arg; }