diff options
author | John (J5) Palmieri <johnp@redhat.com> | 2010-05-28 10:03:11 -0400 |
---|---|---|
committer | John (J5) Palmieri <johnp@redhat.com> | 2010-06-03 13:08:37 -0400 |
commit | 1e42ee6eb25a07a5201f24ffeac18d298a98477e (patch) | |
tree | d152e64c12d69ad1345b3b34f28b4c38d7f977f0 /gi/pygi-invoke.c | |
parent | c3f467e0ae99aa78c2fdb91b973a272d2fe970bd (diff) | |
download | pygobject-1e42ee6eb25a07a5201f24ffeac18d298a98477e.tar.gz |
support for caller-allocates annotations for structs
* out caller-allocates parameters expect an already constructed structure
to be passed in by reference. It is then modified and the caller uses the
modified value. We support this by using only one level of pointer
indirection.
* Only structs are considered to be caller-allocates parameters even if
they are marked as such by GI. This is because the GI scanner isn't smart
enough to correctly guess 100% of the time
* GValues are a special case of a caller-allocates parameter when cleaning
up (e.g. g_value_unset is called). GValues make no sense in a scripting
language. Developers should never deal with them.
https://bugzilla.gnome.org/show_bug.cgi?id=620406
Diffstat (limited to 'gi/pygi-invoke.c')
-rw-r--r-- | gi/pygi-invoke.c | 73 |
1 files changed, 69 insertions, 4 deletions
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c index bf220e71..7ac1685d 100644 --- a/gi/pygi-invoke.c +++ b/gi/pygi-invoke.c @@ -135,7 +135,7 @@ _prepare_invocation_state (struct invocation_state *state, } /* We do a first (well, second) pass here over the function to scan for special cases. - * This is currently array+length combinations and GError. + * This is currently array+length combinations, GError and GValue. */ for (i = 0; i < state->n_args; i++) { GIDirection direction; @@ -298,8 +298,11 @@ _prepare_invocation_state (struct invocation_state *state, for (i = 0; i < state->n_args; i++) { GIDirection direction; + GIBaseInfo *info; + gboolean is_caller_allocates; direction = g_arg_info_get_direction (state->arg_infos[i]); + is_caller_allocates = g_arg_info_is_caller_allocates (state->arg_infos[i]); switch (direction) { case GI_DIRECTION_IN: @@ -310,13 +313,51 @@ _prepare_invocation_state (struct invocation_state *state, case GI_DIRECTION_INOUT: g_assert (in_args_pos < state->n_in_args); g_assert (out_args_pos < state->n_out_args); + state->in_args[in_args_pos].v_pointer = &state->out_values[out_args_pos]; in_args_pos += 1; case GI_DIRECTION_OUT: g_assert (out_args_pos < state->n_out_args); - state->out_args[out_args_pos].v_pointer = &state->out_values[out_args_pos]; - state->out_values[out_args_pos].v_pointer = NULL; - state->args[i] = &state->out_values[out_args_pos]; + + /* caller allocates only applies to structures but GI has + * no way to denote that yet, so we only use caller allocates + * if we see a structure + */ + if (is_caller_allocates) { + GITypeTag type_tag; + + is_caller_allocates = FALSE; + type_tag = g_type_info_get_tag (state->arg_type_infos[i]); + + if (type_tag == GI_TYPE_TAG_INTERFACE) { + GIInfoType info_type; + + info = g_type_info_get_interface (state->arg_type_infos[i]); + g_assert (info != NULL); + info_type = g_base_info_get_type (info); + + if (info_type == GI_INFO_TYPE_STRUCT) + is_caller_allocates = TRUE; + } + } + + if (is_caller_allocates) { + gsize size; + gpointer value; + + /* if caller allocates only use one level of indirection */ + state->out_args[out_args_pos].v_pointer = NULL; + state->args[i] = &state->out_args[out_args_pos]; + + size = g_struct_info_get_size ( (GIStructInfo *) info); + + state->args[i]->v_pointer = g_malloc0 (size); + } else { + state->out_args[out_args_pos].v_pointer = &state->out_values[out_args_pos]; + state->out_values[out_args_pos].v_pointer = NULL; + state->args[i] = &state->out_values[out_args_pos]; + } + out_args_pos += 1; } } @@ -851,6 +892,30 @@ _free_invocation_state (struct invocation_state *state) } for (i = 0; i < state->n_args; i++) { + + /* check for caller-allocated values we need to free */ + if (g_arg_info_is_caller_allocates (state->arg_infos[i])) { + GIBaseInfo *info; + GIInfoType info_type; + + info = g_type_info_get_interface (state->arg_type_infos[i]); + g_assert (info != NULL); + info_type = g_base_info_get_type (info); + + /* caller-allocates applies only to structs right now + * the GI scanner is overzealous when marking parameters + * as caller-allocates, so we only free if this was a struct + */ + if (info_type == GI_INFO_TYPE_STRUCT) { + /* special case GValues so we make sure to unset them */ + if (g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info) == G_TYPE_VALUE) { + g_value_unset ( (GValue *) state->args[i]); + } + + g_free (state->args[i]); + } + } + if (state->arg_type_infos[i] != NULL) g_base_info_unref ( (GIBaseInfo *) state->arg_type_infos[i]); if (state->arg_infos[i] != NULL) |