gperl-i11n-marshal-callback.c 5.46 KB
Newer Older
1 2
/* -*- mode: c; indent-tabs-mode: t; c-basic-offset: 8; -*- */

3
static gpointer
4 5 6 7
sv_to_callback (GIArgInfo * arg_info,
                GITypeInfo * type_info,
                SV * sv,
                GPerlI11nInvocationInfo * invocation_info)
8
{
9
	GIBaseInfo *callback_interface_info;
10 11
	GPerlI11nPerlCallbackInfo *callback_info;
	GIScopeType scope;
12

13
	/* the destroy notify func is handled by _handle_automatic_arg */
14

15
	dwarn ("pos = %d, name = %s\n",
16 17
	       invocation_info->current_pos,
	       g_base_info_get_name (arg_info));
18

19 20
	callback_interface_info = g_type_info_get_interface (type_info);
	callback_info = create_perl_callback_closure (callback_interface_info, sv);
21
	callback_info->data_pos = g_arg_info_get_closure (arg_info);
22
	callback_info->destroy_pos = g_arg_info_get_destroy (arg_info);
23
	callback_info->free_after_use = FALSE;
24
	g_base_info_unref (callback_interface_info);
25

26
	dwarn ("  data at %d, destroy at %d\n",
27
	       callback_info->data_pos, callback_info->destroy_pos);
28

29
	scope = (!gperl_sv_is_defined (sv))
30 31 32
		? GI_SCOPE_TYPE_CALL
		: g_arg_info_get_scope (arg_info);
	switch (scope) {
33
	    case GI_SCOPE_TYPE_CALL:
34
		dwarn ("  scope = 'call'\n");
35 36
		free_after_call (invocation_info,
		                 (GFunc) release_perl_callback, callback_info);
37 38
		break;
	    case GI_SCOPE_TYPE_NOTIFIED:
39
		dwarn ("  scope = 'notified'\n");
40 41 42 43
		/* This case is already taken care of by the notify
		 * stuff above */
		break;
	    case GI_SCOPE_TYPE_ASYNC:
44
		dwarn ("  scope = 'async'\n");
45 46 47 48 49 50 51 52 53 54 55
		/* 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);

56
	dwarn ("  -> closure %p from info %p\n",
57 58 59 60 61
	       callback_info->closure, callback_info);
	return callback_info->closure;
}

static gpointer
62 63
sv_to_callback_data (SV * sv,
                     GPerlI11nInvocationInfo * invocation_info)
64 65
{
	GSList *l;
66 67
	if (!invocation_info)
		return NULL;
68
	for (l = invocation_info->callback_infos; l != NULL; l = l->next) {
69
		GPerlI11nPerlCallbackInfo *callback_info = l->data;
70
		if (callback_info->data_pos == ((gint) invocation_info->current_pos)) {
71
			dwarn ("user data for Perl callback %p\n",
72
			       callback_info);
73
			attach_perl_callback_data (callback_info, sv);
74 75 76 77 78 79 80 81 82 83
			/* If the user did not specify any code and data and if
			 * there is no destroy notify function, then there is
			 * no need for us to pass on our callback info struct
			 * as C user data.  Some libraries (e.g., vte) even
			 * assert that the C user data be NULL if the C
			 * function pointer is NULL. */
			if (!gperl_sv_is_defined (callback_info->code) &&
			    !gperl_sv_is_defined (callback_info->data) &&
			    -1 == callback_info->destroy_pos)
			{
84
				dwarn ("  -> handing over NULL");
85 86
				return NULL;
			}
87
			return callback_info;
88 89
		}
	}
90 91
	if (invocation_info->is_callback) {
		GPerlI11nCCallbackInfo *wrapper = INT2PTR (GPerlI11nCCallbackInfo*, SvIV (sv));
92
		dwarn ("user data for C callback %p\n", wrapper);
93 94 95 96 97 98 99 100
		return wrapper->data;
	}
	return NULL;
}

static SV *
callback_to_sv (GICallableInfo *interface, gpointer func, GPerlI11nInvocationInfo *invocation_info)
{
101
	GIArgInfo arg_info;
102 103 104 105 106 107 108
	GPerlI11nCCallbackInfo *callback_info;
	HV *stash;
	SV *code_sv, *data_sv;

	GSList *l;
	for (l = invocation_info->callback_infos; l != NULL; l = l->next) {
		GPerlI11nCCallbackInfo *callback_info = l->data;
109
		if ((gint) invocation_info->current_pos == callback_info->destroy_pos) {
110
			dwarn ("destroy notify for C callback %p\n",
111 112 113 114 115 116 117 118
			       callback_info);
			callback_info->destroy = func;
			/* release_c_callback is called from
			 * Glib::Object::Introspection::_FuncWrapper::DESTROY */
			return NULL;
		}
	}

119 120 121
	g_callable_info_load_arg (invocation_info->interface,
	                          (gint) invocation_info->current_pos,
	                          &arg_info);
122

123
	dwarn ("C callback: pos = %d, name = %s\n",
124
	       invocation_info->current_pos,
125
	       g_base_info_get_name (&arg_info));
126 127

	callback_info = create_c_callback_closure (interface, func);
128 129
	callback_info->data_pos = g_arg_info_get_closure (&arg_info);
	callback_info->destroy_pos = g_arg_info_get_destroy (&arg_info);
130 131 132 133 134 135 136 137 138 139

	if (func) {
		data_sv = newSViv (PTR2IV (callback_info));
		stash = gv_stashpv ("Glib::Object::Introspection::_FuncWrapper", TRUE);
		code_sv = sv_bless (newRV_noinc (data_sv), stash);
	} else {
		data_sv = code_sv = &PL_sv_undef;
	}
	callback_info->data_sv = data_sv;

140
	dwarn ("  data at %d, destroy at %d\n",
141 142 143 144 145 146 147
	       callback_info->data_pos, callback_info->destroy_pos);


	invocation_info->callback_infos =
		g_slist_prepend (invocation_info->callback_infos,
		                 callback_info);

148
	dwarn ("  -> SV %p from info %p\n",
149 150 151 152 153 154 155 156 157 158 159 160 161
	       code_sv, callback_info);
	return code_sv;
}

static SV *
callback_data_to_sv (gpointer data,
                     GPerlI11nInvocationInfo * invocation_info)
{
	GSList *l;
	if (!invocation_info)
		return NULL;
	for (l = invocation_info->callback_infos; l != NULL; l = l->next) {
		GPerlI11nCCallbackInfo *callback_info = l->data;
162
		if (callback_info->data_pos == (gint) invocation_info->current_pos) {
163
			dwarn ("user data for C callback %p\n",
164 165 166 167 168
			       callback_info);
			attach_c_callback_data (callback_info, data);
			return callback_info->data_sv;
		}
	}
169
	if (data && invocation_info->is_callback) {
170
		GPerlI11nPerlCallbackInfo *wrapper = data;
171
		dwarn ("user data for Perl callback %p\n", wrapper);
172 173
		return wrapper->data;
	}
174
	return NULL;
175
}