static void fill_metadata_callback(GPtrArray *args_metadata) { guint i; for (i = 0; i < args_metadata->len; i++) { RBGIArgMetadata *metadata; GIArgInfo *arg_info; gint closure_index; gint destroy_index; metadata = g_ptr_array_index(args_metadata, i); arg_info = &(metadata->arg_info); closure_index = g_arg_info_get_closure(arg_info); if (closure_index != -1) { RBGIArgMetadata *closure_metadata; closure_metadata = g_ptr_array_index(args_metadata, closure_index); closure_metadata->closure_p = TRUE; metadata->closure_in_arg_index = closure_metadata->in_arg_index; } destroy_index = g_arg_info_get_destroy(arg_info); if (destroy_index != -1) { RBGIArgMetadata *destroy_metadata; destroy_metadata = g_ptr_array_index(args_metadata, destroy_index); destroy_metadata->destroy_p = TRUE; metadata->destroy_in_arg_index = destroy_metadata->in_arg_index; } } }
static gpointer sv_to_callback (GIArgInfo * arg_info, GITypeInfo * type_info, SV * sv, GPerlI11nInvocationInfo * invocation_info) { GIBaseInfo *callback_interface_info; GPerlI11nPerlCallbackInfo *callback_info; GIScopeType scope; /* the destroy notify func is handled by _handle_automatic_arg */ dwarn (" Perl callback at %d (%s)\n", invocation_info->current_pos, g_base_info_get_name (arg_info)); callback_interface_info = g_type_info_get_interface (type_info); callback_info = create_perl_callback_closure (callback_interface_info, sv); callback_info->data_pos = g_arg_info_get_closure (arg_info); callback_info->destroy_pos = g_arg_info_get_destroy (arg_info); callback_info->free_after_use = FALSE; g_base_info_unref (callback_interface_info); dwarn (" Perl callback data at %d, destroy at %d\n", callback_info->data_pos, callback_info->destroy_pos); scope = (!gperl_sv_is_defined (sv)) ? GI_SCOPE_TYPE_CALL : g_arg_info_get_scope (arg_info); switch (scope) { case GI_SCOPE_TYPE_CALL: dwarn (" Perl callback has scope 'call'\n"); free_after_call (invocation_info, (GFunc) release_perl_callback, callback_info); break; case GI_SCOPE_TYPE_NOTIFIED: dwarn (" Perl callback has scope 'notified'\n"); /* This case is already taken care of by the notify * stuff above */ break; case GI_SCOPE_TYPE_ASYNC: dwarn (" Perl callback has scope 'async'\n"); /* FIXME: callback_info->free_after_use = TRUE; */ break; default: ccroak ("unhandled scope type %d encountered", g_arg_info_get_scope (arg_info)); } invocation_info->callback_infos = g_slist_prepend (invocation_info->callback_infos, callback_info); dwarn (" returning Perl closure %p from info %p\n", callback_info->closure, callback_info); return callback_info->closure; }
/* Marshalls given callable from Lua to C. */ static int marshal_2c_callable (lua_State *L, GICallableInfo *ci, GIArgInfo *ai, gpointer *callback, int narg, gboolean optional, GICallableInfo *argci, void **args) { int nret = 0; GIScopeType scope; gpointer user_data = NULL; gint nargs = 0; if (argci != NULL) nargs = g_callable_info_get_n_args (argci); /* Check 'nil' in optional case. In this case, return NULL as callback. */ if (lua_isnoneornil (L, narg)) { if (optional) { *callback = NULL; /* Also set associated destroy handler to NULL, because some callees tend to call it when left as garbage even when main callback is NULL (gtk_menu_popup_for_device() case). */ if (ai != NULL) { gint arg = g_arg_info_get_destroy (ai); if (arg >= 0 && arg < nargs) ((GIArgument *) args[arg])->v_pointer = NULL; } return 0; } else return luaL_argerror (L, narg, "nil is not allowed"); } /* Check lightuserdata case; simply use that data if provided. */ if (lua_islightuserdata (L, narg)) { *callback = lua_touserdata (L, narg); return 0; } if (argci != NULL) { gint arg = g_arg_info_get_closure (ai); /* user_data block is already preallocated from function call. */ g_assert (args != NULL); if (arg >= 0 && arg < nargs) { user_data = ((GIArgument *) args[arg])->v_pointer; arg = g_arg_info_get_destroy (ai); if (arg >= 0 && arg < nargs) ((GIArgument *) args[arg])->v_pointer = lgi_closure_destroy; } } scope = g_arg_info_get_scope (ai); if (user_data == NULL) { /* Closure without user_data block. Create new data block, setup destruction according to scope. */ user_data = lgi_closure_allocate (L, 1); if (scope == GI_SCOPE_TYPE_CALL) { *lgi_guard_create (L, lgi_closure_destroy) = user_data; nret++; } else g_assert (scope == GI_SCOPE_TYPE_ASYNC); } /* Create the closure. */ lgi_callable_create (L, ci, NULL); *callback = lgi_closure_create (L, user_data, narg, scope == GI_SCOPE_TYPE_ASYNC); return nret; }
static gboolean pygi_arg_callback_setup_from_info (PyGICallbackCache *arg_cache, GITypeInfo *type_info, GIArgInfo *arg_info, /* may be null */ GITransfer transfer, PyGIDirection direction, GIInterfaceInfo *iface_info, PyGICallableCache *callable_cache) { PyGIArgCache *cache = (PyGIArgCache *)arg_cache; gssize child_offset = 0; if (!pygi_arg_base_setup ((PyGIArgCache *)arg_cache, type_info, arg_info, transfer, direction)) { return FALSE; } if (callable_cache != NULL) child_offset = callable_cache->args_offset; ( (PyGIArgCache *)arg_cache)->destroy_notify = (GDestroyNotify)_callback_cache_free_func; arg_cache->user_data_index = g_arg_info_get_closure (arg_info); if (arg_cache->user_data_index != -1) arg_cache->user_data_index += child_offset; arg_cache->destroy_notify_index = g_arg_info_get_destroy (arg_info); if (arg_cache->destroy_notify_index != -1) arg_cache->destroy_notify_index += child_offset; if (arg_cache->user_data_index >= 0) { PyGIArgCache *user_data_arg_cache = pygi_arg_cache_alloc (); user_data_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_WITH_PYARG; user_data_arg_cache->direction = direction; user_data_arg_cache->has_default = TRUE; /* always allow user data with a NULL default. */ _pygi_callable_cache_set_arg (callable_cache, arg_cache->user_data_index, user_data_arg_cache); } if (arg_cache->destroy_notify_index >= 0) { PyGIArgCache *destroy_arg_cache = pygi_arg_cache_alloc (); destroy_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; destroy_arg_cache->direction = direction; _pygi_callable_cache_set_arg (callable_cache, arg_cache->destroy_notify_index, destroy_arg_cache); } arg_cache->scope = g_arg_info_get_scope (arg_info); g_base_info_ref( (GIBaseInfo *)iface_info); arg_cache->interface_info = iface_info; if (direction & PYGI_DIRECTION_FROM_PYTHON) { cache->from_py_marshaller = _pygi_marshal_from_py_interface_callback; cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_callback; } if (direction & PYGI_DIRECTION_TO_PYTHON) { cache->to_py_marshaller = _pygi_marshal_to_py_interface_callback; } return TRUE; }
gboolean _pygi_scan_for_callbacks (GIFunctionInfo *function_info, gboolean is_method, guint8 *callback_index, guint8 *user_data_index, guint8 *destroy_notify_index) { guint i, n_args; *callback_index = G_MAXUINT8; *user_data_index = G_MAXUINT8; *destroy_notify_index = G_MAXUINT8; n_args = g_callable_info_get_n_args ( (GICallableInfo *) function_info); for (i = 0; i < n_args; i++) { GIDirection direction; GIArgInfo *arg_info; GITypeInfo *type_info; guint8 destroy, closure; GITypeTag type_tag; arg_info = g_callable_info_get_arg ( (GICallableInfo*) function_info, i); type_info = g_arg_info_get_type (arg_info); type_tag = g_type_info_get_tag (type_info); if (type_tag == GI_TYPE_TAG_INTERFACE) { 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_CALLBACK && ! (strcmp (g_base_info_get_namespace ( (GIBaseInfo*) interface_info), "GLib") == 0 && (strcmp (g_base_info_get_name ( (GIBaseInfo*) interface_info), "DestroyNotify") == 0 || (strcmp (g_base_info_get_name ( (GIBaseInfo*) interface_info), "FreeFunc") == 0)))) { if (*callback_index != G_MAXUINT8) { PyErr_Format (PyExc_TypeError, "Function %s.%s has multiple callbacks, not supported", g_base_info_get_namespace ( (GIBaseInfo*) function_info), g_base_info_get_name ( (GIBaseInfo*) function_info)); g_base_info_unref (interface_info); return FALSE; } *callback_index = i; } g_base_info_unref (interface_info); } destroy = g_arg_info_get_destroy (arg_info); closure = g_arg_info_get_closure (arg_info); direction = g_arg_info_get_direction (arg_info); if (destroy > 0 && destroy < n_args) { if (*destroy_notify_index != G_MAXUINT8) { PyErr_Format (PyExc_TypeError, "Function %s has multiple GDestroyNotify, not supported", g_base_info_get_name ( (GIBaseInfo*) function_info)); return FALSE; } *destroy_notify_index = destroy; } if (closure > 0 && closure < n_args) { if (*user_data_index != G_MAXUINT8) { PyErr_Format (PyExc_TypeError, "Function %s has multiple user_data arguments, not supported", g_base_info_get_name ( (GIBaseInfo*) function_info)); return FALSE; } *user_data_index = closure; } g_base_info_unref ( (GIBaseInfo*) arg_info); g_base_info_unref ( (GIBaseInfo*) type_info); } return TRUE; }