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 )