Glib
view release on metacpan or search on metacpan
GClosure.xs view on Meta::CPAN
}
=item void gperl_callback_invoke (GPerlCallback * callback, GValue * return_value, ...)
Marshall the variadic parameters according to I<callback>'s param_types, and
then invoke I<callback>'s subroutine in scalar context, or void context if the
return type is G_TYPE_VOID. If I<return_value> is not NULL, then value
returned (if any) will be copied into I<return_value>.
A typical callback handler would look like this:
static gint
real_c_callback (Foo * f, Bar * b, int a, gpointer data)
{
GPerlCallback * callback = (GPerlCallback*)data;
GValue return_value = {0,};
gint retval;
g_value_init (&return_value, callback->return_type);
gperl_callback_invoke (callback, &return_value,
f, b, a);
retval = g_value_get_int (&return_value);
g_value_unset (&return_value);
return retval;
}
=cut
void
gperl_callback_invoke (GPerlCallback * callback,
GValue * return_value,
...)
{
va_list var_args;
dGPERL_CALLBACK_MARSHAL_SP;
g_return_if_fail (callback != NULL);
GPERL_CALLBACK_MARSHAL_INIT (callback);
ENTER;
SAVETMPS;
PUSHMARK (SP);
va_start (var_args, return_value);
/* put args on the stack */
if (callback->n_params > 0) {
int i;
GValue v = {0, };
/* Crib note: must g_value_unset() even when asking for
* G_VALUE_NOCOPY_CONTENTS. A GObject is always
* g_object_ref()ed for storage in a GValue, even under
* G_VALUE_NOCOPY_CONTENTS (see code in
* g_value_object_collect_value()). Always reffing in
* G_VALUE_COLLECT is in fact the recommended behaviour for
* all ref-counted types (see the GTypeValueTable docs,
* apparently to ensure objects remain alive for the
* duration of a g_signal_emit_valist()).
*/
for (i = 0 ; i < callback->n_params ; i++) {
gchar * error = NULL;
SV * sv;
g_value_init (&v, callback->param_types[i]);
G_VALUE_COLLECT (&v, var_args, G_VALUE_NOCOPY_CONTENTS,
&error);
if (error) {
SV * errstr;
/* this should only happen if you've
* created the callback incorrectly */
/* we modified the stack -- we need to make
* sure perl sees that! */
PUTBACK;
errstr = newSVpvf ("error while collecting"
" varargs parameters: %s\n"
"is your GPerlCallback "
"created properly? "
" bailing out",
error);
g_free (error);
/* this won't return */
croak ("%s", SvPV_nolen (errstr));
}
sv = SAVED_STACK_SV (gperl_sv_from_value (&v));
g_value_unset (&v);
if (!sv) {
/* this should be very rare, too. */
PUTBACK;
croak ("failed to convert GValue to SV");
}
XPUSHs (sv_2mortal (sv));
}
}
/* Usual REFCNT_inc and 2mortal here for putting something on the
* stack. It's possible callback->func will disconnect itself, in
* which case gperl_callback_destroy() will REFCNT_dec the data.
* That's fine, it leaves the mortal ref on the stack as the only
* one remaining, and the next FREETMPS will decrement and destroy
* in the usual way.
*
* Being a plain push here means callback->func can modify its
* $_[-1] to modify the stored userdata. Slightly scary, but it's a
* cute way to get a free bit of per-connection data you can play
* with as a state variable or whatnot. And not making a copy saves
* a couple of bytes of memory :-).
*/
{
SV *data = callback->data;
if (data) {
XPUSHs (sv_2mortal (SvREFCNT_inc (data)));
}
}
va_end (var_args);
PUTBACK;
/* invoke the callback */
( run in 2.252 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )