gobject-introspection 1.1.9 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -72,7 +72,7 @@ rg_n_args(VALUE self)
72
72
  }
73
73
 
74
74
  static VALUE
75
- rg_operator_aref(VALUE self, VALUE rb_n)
75
+ rg_get_arg(VALUE self, VALUE rb_n)
76
76
  {
77
77
  GICallableInfo *info;
78
78
  gint n;
@@ -82,25 +82,6 @@ rg_operator_aref(VALUE self, VALUE rb_n)
82
82
  return GI_BASE_INFO2RVAL_WITH_UNREF(g_callable_info_get_arg(info, n));
83
83
  }
84
84
 
85
- static VALUE
86
- rg_args(VALUE self)
87
- {
88
- GICallableInfo *info;
89
- gint i, n;
90
- VALUE rb_args;
91
-
92
- info = SELF(self);
93
- rb_args = rb_ary_new();
94
- n = g_callable_info_get_n_args(info);
95
- for (i = 0; i < n; i++) {
96
- GIArgInfo *arg_info;
97
- arg_info = g_callable_info_get_arg(info, i);
98
- rb_ary_push(rb_args, GI_BASE_INFO2RVAL_WITH_UNREF(arg_info));
99
- }
100
-
101
- return rb_args;
102
- }
103
-
104
85
  void
105
86
  rb_gi_callable_info_init(VALUE rb_mGI, VALUE rb_cGIBaseInfo)
106
87
  {
@@ -114,8 +95,7 @@ rb_gi_callable_info_init(VALUE rb_mGI, VALUE rb_cGIBaseInfo)
114
95
  RG_DEF_METHOD(caller_owns, 0);
115
96
  RG_DEF_METHOD_P(may_return_null, 0);
116
97
  RG_DEF_METHOD(n_args, 0);
117
- RG_DEF_METHOD_OPERATOR("[]", aref, 1);
118
- RG_DEF_METHOD(args, 0);
98
+ RG_DEF_METHOD(get_arg, 1);
119
99
 
120
100
  rb_gi_function_info_init(rb_mGI, RG_TARGET_NAMESPACE);
121
101
  rb_gi_callback_info_init(rb_mGI, RG_TARGET_NAMESPACE);
@@ -35,6 +35,52 @@ gi_constructor_info_get_type(void)
35
35
  return type;
36
36
  }
37
37
 
38
+ static void
39
+ initialize_receiver(VALUE receiver, GITypeInfo *info, GIArgument *value)
40
+ {
41
+ GIBaseInfo *interface_info;
42
+ GIInfoType interface_type;
43
+
44
+ if (g_type_info_get_tag(info) != GI_TYPE_TAG_INTERFACE) {
45
+ rb_raise(rb_eRuntimeError, "TODO: returned value isn't interface");
46
+ }
47
+
48
+ interface_info = g_type_info_get_interface(info);
49
+ interface_type = g_base_info_get_type(interface_info);
50
+ g_base_info_unref(interface_info);
51
+ switch (interface_type) {
52
+ case GI_INFO_TYPE_OBJECT:
53
+ g_object_ref_sink(value->v_pointer);
54
+ G_INITIALIZE(receiver, value->v_pointer);
55
+ break;
56
+ case GI_INFO_TYPE_STRUCT:
57
+ G_INITIALIZE(receiver, value->v_pointer);
58
+ break;
59
+ case GI_INFO_TYPE_INVALID:
60
+ case GI_INFO_TYPE_FUNCTION:
61
+ case GI_INFO_TYPE_CALLBACK:
62
+ case GI_INFO_TYPE_BOXED:
63
+ case GI_INFO_TYPE_ENUM:
64
+ case GI_INFO_TYPE_FLAGS:
65
+ case GI_INFO_TYPE_INTERFACE:
66
+ case GI_INFO_TYPE_CONSTANT:
67
+ case GI_INFO_TYPE_INVALID_0:
68
+ case GI_INFO_TYPE_UNION:
69
+ case GI_INFO_TYPE_VALUE:
70
+ case GI_INFO_TYPE_SIGNAL:
71
+ case GI_INFO_TYPE_VFUNC:
72
+ case GI_INFO_TYPE_PROPERTY:
73
+ case GI_INFO_TYPE_FIELD:
74
+ case GI_INFO_TYPE_ARG:
75
+ case GI_INFO_TYPE_TYPE:
76
+ case GI_INFO_TYPE_UNRESOLVED:
77
+ default:
78
+ rb_raise(rb_eRuntimeError,
79
+ "TODO: returned value isn't object or struct");
80
+ break;
81
+ }
82
+ }
83
+
38
84
  static VALUE
39
85
  rg_invoke(int argc, VALUE *argv, VALUE self)
40
86
  {
@@ -43,27 +89,19 @@ rg_invoke(int argc, VALUE *argv, VALUE self)
43
89
  VALUE receiver;
44
90
  GIArgument return_value;
45
91
  GITypeInfo return_value_info;
46
- GIBaseInfo *interface_info;
47
- GIInfoType interface_type;
48
92
 
49
93
  info = SELF(self);
50
94
  callable_info = (GICallableInfo *)info;
51
95
 
52
96
  /* TODO: check argc. */
53
97
  receiver = argv[0];
54
- rb_gi_function_info_invoke_raw(info, argc - 1, argv + 1, &return_value);
55
- g_callable_info_load_return_type(callable_info, &return_value_info);
98
+ /* TODO: use rb_protect */
99
+ rb_gi_function_info_invoke_raw(info, NULL,
100
+ argc - 1, argv + 1,
101
+ &return_value);
56
102
 
57
- if (g_type_info_get_tag(&return_value_info) != GI_TYPE_TAG_INTERFACE) {
58
- rb_raise(rb_eRuntimeError, "TODO: returned value isn't interface");
59
- }
60
- interface_info = g_type_info_get_interface(&return_value_info);
61
- interface_type = g_base_info_get_type(interface_info);
62
- if (interface_type != GI_INFO_TYPE_OBJECT) {
63
- rb_raise(rb_eRuntimeError, "TODO: returned value isn't object");
64
- }
65
- g_object_ref_sink(return_value.v_pointer);
66
- G_INITIALIZE(receiver, return_value.v_pointer);
103
+ g_callable_info_load_return_type(callable_info, &return_value_info);
104
+ initialize_receiver(receiver, &return_value_info, &return_value);
67
105
 
68
106
  return receiver;
69
107
  }
@@ -1,6 +1,6 @@
1
1
  /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
2
  /*
3
- * Copyright (C) 2012 Ruby-GNOME2 Project Team
3
+ * Copyright (C) 2012-2013 Ruby-GNOME2 Project Team
4
4
  *
5
5
  * This library is free software; you can redistribute it and/or
6
6
  * modify it under the terms of the GNU Lesser General Public
@@ -33,8 +33,14 @@
33
33
 
34
34
  #define GI_ARGUMENT2RVAL(argument, type_info) \
35
35
  (rb_gi_argument_to_ruby((argument), (type_info)))
36
- #define RVAL2GI_ARGUMENT(argument, type_info, rb_argument) \
37
- (rb_gi_argument_from_ruby((argument), (type_info), (rb_argument)))
36
+ #define GI_OUT_ARGUMENT2RVAL(argument, arg_info) \
37
+ (rb_gi_out_argument_to_ruby((argument), (arg_info)))
38
+ #define GI_RETURN_ARGUMENT2RVAL(argument, callable_info) \
39
+ (rb_gi_return_argument_to_ruby((argument), (callable_info)))
40
+ #define RVAL2GI_IN_ARGUMENT(argument, type_info, rb_argument) \
41
+ (rb_gi_in_argument_from_ruby((argument), (type_info), (rb_argument)))
42
+ #define RVAL2GI_CALL_ARGUMENT(argument, arg_info, rb_argument) \
43
+ (rb_gi_call_argument_from_ruby((argument), (arg_info), (rb_argument)))
38
44
 
39
45
 
40
46
  #define RVAL2GI_REGISTERED_TYPE_INFO(rb_object) \
@@ -83,11 +89,26 @@ VALUE rb_gi_base_info_to_ruby (GIBaseInfo *info);
83
89
  VALUE rb_gi_base_info_to_ruby_with_unref(GIBaseInfo *info);
84
90
  GIBaseInfo *rb_gi_base_info_from_ruby (VALUE rb_info);
85
91
 
86
- VALUE rb_gi_argument_to_ruby (GIArgument *argument,
87
- GITypeInfo *type_info);
88
- GIArgument *rb_gi_argument_from_ruby (GIArgument *argument,
89
- GITypeInfo *type_info,
90
- VALUE rb_argument);
92
+ VALUE rb_gi_argument_to_ruby (GIArgument *argument,
93
+ GITypeInfo *type_info);
94
+ void rb_gi_out_argument_init (GIArgument *argument,
95
+ GIArgInfo *arg_info);
96
+ VALUE rb_gi_out_argument_to_ruby (GIArgument *argument,
97
+ GIArgInfo *arg_info);
98
+ void rb_gi_out_argument_fin (GIArgument *argument,
99
+ GIArgInfo *arg_info);
100
+ VALUE rb_gi_return_argument_to_ruby (GIArgument *argument,
101
+ GICallableInfo *callable_info);
102
+ GIArgument *rb_gi_in_argument_from_ruby (GIArgument *argument,
103
+ GITypeInfo *type_info,
104
+ VALUE rb_argument);
105
+ GIArgument *rb_gi_call_argument_from_ruby (GIArgument *argument,
106
+ GIArgInfo *arg_info,
107
+ VALUE rb_argument);
108
+ void rb_gi_in_argument_free (GIArgument *argument,
109
+ GITypeInfo *type_info);
110
+ void rb_gi_call_argument_free (GIArgument *argument,
111
+ GIArgInfo *arg_info);
91
112
 
92
113
  VALUE rb_gi_array_type_to_ruby (GIArrayType type);
93
114
 
@@ -1,6 +1,6 @@
1
1
  /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
2
  /*
3
- * Copyright (C) 2012 Ruby-GNOME2 Project Team
3
+ * Copyright (C) 2012-2013 Ruby-GNOME2 Project Team
4
4
  *
5
5
  * This library is free software; you can redistribute it and/or
6
6
  * modify it under the terms of the GNU Lesser General Public
@@ -95,12 +95,16 @@ rb_gi_field_info_set_field_raw(GIFieldInfo *info, gpointer memory,
95
95
  {
96
96
  GIArgument field_value;
97
97
  GITypeInfo *type_info;
98
+ gboolean succeeded;
98
99
 
99
100
  type_info = g_field_info_get_type(info);
100
- RVAL2GI_ARGUMENT(&field_value, type_info, rb_field_value);
101
+ RVAL2GI_IN_ARGUMENT(&field_value, type_info, rb_field_value);
102
+
103
+ succeeded = g_field_info_set_field(info, memory, &field_value);
104
+ rb_gi_in_argument_free(&field_value, type_info);
101
105
  g_base_info_unref(type_info);
102
106
 
103
- if (!g_field_info_set_field(info, memory, &field_value)) {
107
+ if (!succeeded) {
104
108
  rb_raise(rb_eArgError, "failed to set field value");
105
109
  }
106
110
  }
@@ -1,6 +1,6 @@
1
1
  /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
2
  /*
3
- * Copyright (C) 2012 Ruby-GNOME2 Project Team
3
+ * Copyright (C) 2012-2013 Ruby-GNOME2 Project Team
4
4
  *
5
5
  * This library is free software; you can redistribute it and/or
6
6
  * modify it under the terms of the GNU Lesser General Public
@@ -23,6 +23,9 @@
23
23
  #define RG_TARGET_NAMESPACE rb_cGIFunctionInfo
24
24
  #define SELF(self) RVAL2GI_FUNCTION_INFO(self)
25
25
 
26
+ static VALUE RG_TARGET_NAMESPACE;
27
+ static const char *callbacks_key = "gi_callbacks";
28
+
26
29
  GType
27
30
  gi_function_info_get_type(void)
28
31
  {
@@ -71,81 +74,478 @@ rg_vfunc(VALUE self)
71
74
  return GI_BASE_INFO2RVAL(g_function_info_get_vfunc(info));
72
75
  }
73
76
 
77
+ typedef struct
78
+ {
79
+ GIArgInfo arg_info;
80
+ GIScopeType scope_type;
81
+ GIDirection direction;
82
+ gboolean callback_p;
83
+ gboolean closure_p;
84
+ gboolean destroy_p;
85
+ gboolean inout_argv_p;
86
+ gint in_arg_index;
87
+ gint closure_in_arg_index;
88
+ gint destroy_in_arg_index;
89
+ gint rb_arg_index;
90
+ gint out_arg_index;
91
+ gint inout_argc_arg_index;
92
+ } ArgMetadata;
93
+
74
94
  static void
75
- fill_gi_argument_by_ruby(GIArgument *argument, GIArgInfo *arg_info,
76
- VALUE rb_argument)
95
+ allocate_arguments(GICallableInfo *info,
96
+ GArray *in_args, GArray *out_args,
97
+ GPtrArray *args_metadata)
98
+ {
99
+ gint i, n_args;
100
+ gint rb_arg_index = 0;
101
+
102
+ n_args = g_callable_info_get_n_args(info);
103
+ for (i = 0; i < n_args; i++) {
104
+ GIArgument argument;
105
+ ArgMetadata *metadata;
106
+ GIArgInfo *arg_info;
107
+ GIDirection direction;
108
+
109
+ memset(&argument, 0, sizeof(GIArgument));
110
+
111
+ metadata = ALLOC(ArgMetadata);
112
+ arg_info = &(metadata->arg_info);
113
+ g_callable_info_load_arg(info, i, arg_info);
114
+ metadata->scope_type = g_arg_info_get_scope(arg_info);
115
+ metadata->direction = g_arg_info_get_direction(arg_info);
116
+ metadata->callback_p = (metadata->scope_type != GI_SCOPE_TYPE_INVALID);
117
+ metadata->closure_p = FALSE;
118
+ metadata->destroy_p = FALSE;
119
+ metadata->inout_argv_p = FALSE;
120
+ metadata->in_arg_index = -1;
121
+ metadata->closure_in_arg_index = -1;
122
+ metadata->destroy_in_arg_index = -1;
123
+ metadata->rb_arg_index = -1;
124
+ metadata->out_arg_index = -1;
125
+ metadata->inout_argc_arg_index = -1;
126
+
127
+ direction = metadata->direction;
128
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
129
+ metadata->in_arg_index = in_args->len;
130
+ g_array_append_val(in_args, argument);
131
+ metadata->rb_arg_index = rb_arg_index++;
132
+ }
133
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
134
+ metadata->out_arg_index = out_args->len;
135
+ g_array_append_val(out_args, argument);
136
+ }
137
+
138
+ g_ptr_array_add(args_metadata, metadata);
139
+ }
140
+ }
141
+
142
+ static void
143
+ fill_metadata_inout_argv(GPtrArray *args_metadata)
144
+ {
145
+ guint i;
146
+ gint inout_argc_arg_index = -1;
147
+
148
+ for (i = 0; i < args_metadata->len; i++) {
149
+ ArgMetadata *metadata;
150
+ GIArgInfo *arg_info;
151
+ const gchar *name;
152
+
153
+ metadata = g_ptr_array_index(args_metadata, i);
154
+ if (metadata->direction != GI_DIRECTION_INOUT) {
155
+ continue;
156
+ }
157
+ arg_info = &(metadata->arg_info);
158
+ name = g_base_info_get_name(arg_info);
159
+ if (strcmp(name, "argc") == 0) {
160
+ inout_argc_arg_index = i;
161
+ } else if (strcmp(name, "argv") == 0) {
162
+ metadata->inout_argv_p = TRUE;
163
+ metadata->inout_argc_arg_index = inout_argc_arg_index;
164
+ }
165
+ }
166
+ }
167
+
168
+ static void
169
+ fill_metadata_callback(GPtrArray *args_metadata)
170
+ {
171
+ guint i;
172
+
173
+ for (i = 0; i < args_metadata->len; i++) {
174
+ ArgMetadata *metadata;
175
+ GIArgInfo *arg_info;
176
+ gint closure_index;
177
+ gint destroy_index;
178
+
179
+ metadata = g_ptr_array_index(args_metadata, i);
180
+ if (!metadata->callback_p) {
181
+ continue;
182
+ }
183
+
184
+ arg_info = &(metadata->arg_info);
185
+ closure_index = g_arg_info_get_closure(arg_info);
186
+ if (closure_index != -1) {
187
+ ArgMetadata *closure_metadata;
188
+ closure_metadata = g_ptr_array_index(args_metadata, closure_index);
189
+ closure_metadata->closure_p = TRUE;
190
+ metadata->closure_in_arg_index = closure_metadata->in_arg_index;
191
+ closure_metadata->rb_arg_index = -1;
192
+ }
193
+
194
+ destroy_index = g_arg_info_get_destroy(arg_info);
195
+ if (destroy_index != -1) {
196
+ ArgMetadata *destroy_metadata;
197
+ destroy_metadata = g_ptr_array_index(args_metadata, destroy_index);
198
+ destroy_metadata->destroy_p = TRUE;
199
+ metadata->destroy_in_arg_index = destroy_metadata->in_arg_index;
200
+ destroy_metadata->rb_arg_index = -1;
201
+ }
202
+ }
203
+ }
204
+
205
+ static void
206
+ fill_metadata(GPtrArray *args_metadata)
207
+ {
208
+ fill_metadata_inout_argv(args_metadata);
209
+ fill_metadata_callback(args_metadata);
210
+ }
211
+
212
+ static gboolean
213
+ source_callback_p(GIArgInfo *info)
77
214
  {
78
215
  GITypeInfo type_info;
216
+ GIBaseInfo *interface_info;
217
+ GICallableInfo *callback_info;
218
+ GITypeInfo return_type_info;
219
+ GIArgInfo first_arg_info;
220
+ GITypeInfo first_arg_type_info;
221
+
222
+ g_arg_info_load_type(info, &type_info);
223
+ if (g_type_info_get_tag(&type_info) != GI_TYPE_TAG_INTERFACE) {
224
+ return FALSE;
225
+ }
79
226
 
80
- g_arg_info_load_type(arg_info, &type_info);
81
- RVAL2GI_ARGUMENT(argument, &type_info, rb_argument);
227
+ interface_info = g_type_info_get_interface(&type_info);
228
+ if (g_base_info_get_type(interface_info) != GI_INFO_TYPE_CALLBACK) {
229
+ g_base_info_unref(interface_info);
230
+ return FALSE;
231
+ }
232
+
233
+ callback_info = (GICallableInfo *)interface_info;
234
+ g_callable_info_load_return_type(callback_info, &return_type_info);
235
+ if (g_type_info_get_tag(&return_type_info) != GI_TYPE_TAG_BOOLEAN) {
236
+ g_base_info_unref(interface_info);
237
+ return FALSE;
238
+ }
239
+
240
+ if (g_callable_info_get_n_args(interface_info) != 1) {
241
+ g_base_info_unref(interface_info);
242
+ return FALSE;
243
+ }
244
+
245
+ g_callable_info_load_arg(interface_info, 0, &first_arg_info);
246
+ g_arg_info_load_type(&first_arg_info, &first_arg_type_info);
247
+ if (g_type_info_get_tag(&first_arg_type_info) != GI_TYPE_TAG_VOID) {
248
+ g_base_info_unref(interface_info);
249
+ return FALSE;
250
+ }
251
+
252
+ g_base_info_unref(interface_info);
253
+ return TRUE;
82
254
  }
83
255
 
256
+ typedef struct {
257
+ ArgMetadata *metadata;
258
+ VALUE rb_gc_guard_key;
259
+ VALUE rb_callback;
260
+ } CallbackData;
261
+
84
262
  static void
85
- fill_in_argument(GIArgInfo *arg_info, GArray *in_args, int argc, VALUE *argv)
263
+ callback_data_guard_from_gc(CallbackData *callback_data)
86
264
  {
87
- VALUE rb_argument;
88
- GIArgument argument;
265
+ VALUE rb_callbacks;
89
266
 
90
- /* TODO: check argc */
91
- rb_argument = argv[in_args->len];
92
- fill_gi_argument_by_ruby(&argument, arg_info, rb_argument);
93
- g_array_append_val(in_args, argument);
267
+ rb_callbacks = rb_iv_get(RG_TARGET_NAMESPACE, callbacks_key);
268
+ callback_data->rb_gc_guard_key = rb_class_new_instance(0, NULL, rb_cObject);
269
+ rb_hash_aset(rb_callbacks,
270
+ callback_data->rb_gc_guard_key,
271
+ callback_data->rb_callback);
94
272
  }
95
273
 
96
274
  static void
97
- fill_out_argument(G_GNUC_UNUSED GIArgInfo *arg_info, GArray *out_args)
275
+ callback_data_unguard_from_gc(CallbackData *callback_data)
98
276
  {
99
- GIArgument argument;
100
- g_array_append_val(out_args, argument);
277
+ VALUE rb_callbacks;
278
+
279
+ rb_callbacks = rb_iv_get(RG_TARGET_NAMESPACE, callbacks_key);
280
+ rb_hash_delete(rb_callbacks, callback_data->rb_gc_guard_key);
101
281
  }
102
282
 
103
283
  static void
104
- fill_argument(GIArgInfo *arg_info, GArray *in_args, GArray *out_args,
105
- int argc, VALUE *argv)
106
- {
107
- switch (g_arg_info_get_direction(arg_info)) {
108
- case GI_DIRECTION_IN:
109
- fill_in_argument(arg_info, in_args, argc, argv);
110
- break;
111
- case GI_DIRECTION_OUT:
112
- fill_out_argument(arg_info, out_args);
113
- break;
114
- case GI_DIRECTION_INOUT:
115
- fill_in_argument(arg_info, in_args, argc, argv);
116
- fill_out_argument(arg_info, out_args);
117
- break;
118
- default:
119
- g_assert_not_reached();
120
- break;
284
+ callback_data_free(CallbackData *callback_data)
285
+ {
286
+ callback_data_unguard_from_gc(callback_data);
287
+ xfree(callback_data->metadata);
288
+ xfree(callback_data);
289
+ }
290
+
291
+ static gboolean
292
+ source_callback(gpointer user_data)
293
+ {
294
+ CallbackData *callback_data = user_data;
295
+ VALUE rb_keep;
296
+ ID id_call;
297
+
298
+ CONST_ID(id_call, "call");
299
+ rb_keep = rb_funcall(callback_data->rb_callback, id_call, 0);
300
+ if (callback_data->metadata->scope_type == GI_SCOPE_TYPE_ASYNC) {
301
+ callback_data_free(callback_data);
121
302
  }
303
+ return RVAL2CBOOL(rb_keep);
122
304
  }
123
305
 
124
- void
125
- rb_gi_function_info_invoke_raw(GIFunctionInfo *info, int argc, VALUE *argv,
306
+ static void
307
+ destroy_notify(gpointer data)
308
+ {
309
+ CallbackData *callback_data = data;
310
+ callback_data_free(callback_data);
311
+ }
312
+
313
+ static void
314
+ in_callback_argument_from_ruby(ArgMetadata *metadata, VALUE *argv,
315
+ GArray *in_args)
316
+ {
317
+ GIArgument *callback_argument;
318
+
319
+ if (!source_callback_p(&(metadata->arg_info))) {
320
+ rb_raise(rb_eNotImpError,
321
+ "TODO: GSourceFunc callback is only supported.");
322
+ }
323
+
324
+ callback_argument = &(g_array_index(in_args,
325
+ GIArgument,
326
+ metadata->in_arg_index));
327
+ callback_argument->v_pointer = source_callback;
328
+
329
+ if (metadata->closure_in_arg_index != -1) {
330
+ CallbackData *callback_data;
331
+ GIArgument *closure_argument;
332
+
333
+ callback_data = ALLOC(CallbackData);
334
+ callback_data->metadata = metadata;
335
+ callback_data->rb_callback = rb_block_proc();
336
+ callback_data_guard_from_gc(callback_data);
337
+ closure_argument = &(g_array_index(in_args,
338
+ GIArgument,
339
+ metadata->closure_in_arg_index));
340
+ closure_argument->v_pointer = callback_data;
341
+ }
342
+
343
+ if (metadata->destroy_in_arg_index != -1) {
344
+ GIArgument *destroy_argument;
345
+ destroy_argument = &(g_array_index(in_args,
346
+ GIArgument,
347
+ metadata->destroy_in_arg_index));
348
+ destroy_argument->v_pointer = destroy_notify;
349
+ }
350
+ }
351
+
352
+ static void
353
+ in_argument_from_ruby(ArgMetadata *metadata, VALUE *argv, GArray *in_args)
354
+ {
355
+ if (metadata->rb_arg_index == -1) {
356
+ return;
357
+ }
358
+
359
+ if (metadata->callback_p) {
360
+ in_callback_argument_from_ruby(metadata, argv, in_args);
361
+ } else {
362
+ GIArgument *argument;
363
+
364
+ argument = &(g_array_index(in_args, GIArgument, metadata->in_arg_index));
365
+ RVAL2GI_CALL_ARGUMENT(argument,
366
+ &(metadata->arg_info),
367
+ argv[metadata->rb_arg_index]);
368
+ }
369
+ }
370
+
371
+ static void
372
+ out_argument_from_ruby(ArgMetadata *metadata, GArray *out_args)
373
+ {
374
+ GIArgument *argument;
375
+
376
+ argument = &(g_array_index(out_args, GIArgument, metadata->out_arg_index));
377
+ rb_gi_out_argument_init(argument, &(metadata->arg_info));
378
+ }
379
+
380
+ static void
381
+ arg_metadata_free(gpointer data)
382
+ {
383
+ ArgMetadata *metadata = data;
384
+ if (metadata->scope_type == GI_SCOPE_TYPE_ASYNC ||
385
+ metadata->scope_type == GI_SCOPE_TYPE_NOTIFIED) {
386
+ return;
387
+ }
388
+ xfree(metadata);
389
+ }
390
+
391
+ static void
392
+ arguments_from_ruby(GICallableInfo *info,
393
+ int argc, VALUE *argv,
394
+ GArray *in_args, GArray *out_args,
395
+ GPtrArray *args_metadata)
396
+ {
397
+ gint i, n_args;
398
+
399
+ allocate_arguments(info, in_args, out_args, args_metadata);
400
+ fill_metadata(args_metadata);
401
+
402
+ /* TODO: validate_rb_args(args_metadata); */
403
+
404
+ n_args = g_callable_info_get_n_args(info);
405
+ for (i = 0; i < n_args; i++) {
406
+ ArgMetadata *metadata;
407
+
408
+ metadata = g_ptr_array_index(args_metadata, i);
409
+ if (metadata->in_arg_index != -1) {
410
+ in_argument_from_ruby(metadata, argv, in_args);
411
+ } else {
412
+ out_argument_from_ruby(metadata, out_args);
413
+ }
414
+ }
415
+ }
416
+
417
+ static VALUE
418
+ inout_argv_argument_to_ruby(GArray *in_args, ArgMetadata *metadata)
419
+ {
420
+ GIArgument *inout_argc_argument;
421
+ GIArgument *inout_argv_argument;
422
+ gint i, argc;
423
+ gchar **argv;
424
+ VALUE rb_argv_argument;
425
+
426
+ inout_argc_argument = &g_array_index(in_args, GIArgument,
427
+ metadata->inout_argc_arg_index);
428
+ inout_argv_argument = &g_array_index(in_args, GIArgument,
429
+ metadata->in_arg_index);
430
+ argc = *((gint *)(inout_argc_argument->v_pointer));
431
+ argv = *((gchar ***)(inout_argv_argument->v_pointer));
432
+ rb_argv_argument = rb_ary_new2(argc);
433
+ for (i = 0; i < argc; i++) {
434
+ rb_ary_push(rb_argv_argument, CSTR2RVAL(argv[i]));
435
+ }
436
+ return rb_argv_argument;
437
+ }
438
+
439
+ static VALUE
440
+ out_arguments_to_ruby(GICallableInfo *callable_info,
441
+ GArray *in_args, GArray *out_args,
442
+ GPtrArray *args_metadata)
443
+ {
444
+ gint i, n_args;
445
+ VALUE rb_out_args;
446
+
447
+ rb_out_args = rb_ary_new();
448
+ n_args = g_callable_info_get_n_args(callable_info);
449
+ for (i = 0; i < n_args; i++) {
450
+ ArgMetadata *metadata;
451
+ GIArgument *argument = NULL;
452
+ VALUE rb_argument;
453
+
454
+ metadata = g_ptr_array_index(args_metadata, i);
455
+ switch (metadata->direction) {
456
+ case GI_DIRECTION_IN:
457
+ break;
458
+ case GI_DIRECTION_OUT:
459
+ argument = &g_array_index(out_args, GIArgument,
460
+ metadata->out_arg_index);
461
+ break;
462
+ case GI_DIRECTION_INOUT:
463
+ argument = &g_array_index(in_args, GIArgument,
464
+ metadata->in_arg_index);
465
+ break;
466
+ default:
467
+ g_assert_not_reached();
468
+ break;
469
+ }
470
+
471
+ if (!argument) {
472
+ continue;
473
+ }
474
+
475
+ if (metadata->inout_argv_p) {
476
+ rb_argument = inout_argv_argument_to_ruby(in_args, metadata);
477
+ } else {
478
+ rb_argument = GI_OUT_ARGUMENT2RVAL(argument, &(metadata->arg_info));
479
+ }
480
+ rb_ary_push(rb_out_args, rb_argument);
481
+ }
482
+
483
+ if (RARRAY_LEN(rb_out_args) == 0) {
484
+ return Qnil;
485
+ } else {
486
+ return rb_out_args;
487
+ }
488
+ }
489
+
490
+ static void
491
+ arguments_init(GArray **in_args, GArray **out_args, GPtrArray **args_metadata)
492
+ {
493
+ *in_args = g_array_new(FALSE, FALSE, sizeof(GIArgument));
494
+ *out_args = g_array_new(FALSE, FALSE, sizeof(GIArgument));
495
+ *args_metadata = g_ptr_array_new_with_free_func(arg_metadata_free);
496
+ }
497
+
498
+ static void
499
+ arguments_free(GArray *in_args, GArray *out_args, GPtrArray *args_metadata)
500
+ {
501
+ guint i;
502
+
503
+ for (i = 0; i < args_metadata->len; i++) {
504
+ ArgMetadata *metadata;
505
+ gint in_arg_index;
506
+
507
+ metadata = g_ptr_array_index(args_metadata, i);
508
+ if (metadata->direction == GI_DIRECTION_IN ||
509
+ metadata->direction == GI_DIRECTION_INOUT) {
510
+ in_arg_index = metadata->in_arg_index;
511
+ if (in_arg_index != -1) {
512
+ GIArgument *argument;
513
+ argument = &(g_array_index(in_args, GIArgument, in_arg_index));
514
+ rb_gi_call_argument_free(argument, &(metadata->arg_info));
515
+ }
516
+ } else {
517
+ GIArgument *argument;
518
+ argument = &(g_array_index(out_args, GIArgument,
519
+ metadata->out_arg_index));
520
+ rb_gi_out_argument_fin(argument, &(metadata->arg_info));
521
+ }
522
+ }
523
+
524
+ g_array_unref(in_args);
525
+ g_array_unref(out_args);
526
+ g_ptr_array_unref(args_metadata);
527
+ }
528
+
529
+ VALUE
530
+ rb_gi_function_info_invoke_raw(GIFunctionInfo *info, GIArgument *receiver,
531
+ int argc, VALUE *argv,
126
532
  GIArgument *return_value)
127
533
  {
128
534
  GICallableInfo *callable_info;
129
- gint i, n_args;
130
535
  GArray *in_args, *out_args;
536
+ GPtrArray *args_metadata;
537
+ VALUE rb_out_args = Qnil;
131
538
  gboolean succeeded;
132
539
  GError *error = NULL;
133
540
 
134
541
  callable_info = (GICallableInfo *)info;
135
- n_args = g_callable_info_get_n_args(callable_info);
136
- in_args = g_array_new(FALSE, FALSE, sizeof(GIArgument));
137
- out_args = g_array_new(FALSE, FALSE, sizeof(GIArgument));
138
- if (g_function_info_get_flags(callable_info) & GI_FUNCTION_IS_METHOD) {
139
- GIArgument argument;
140
- /* TODO: check argc */
141
- argument.v_pointer = RVAL2GOBJ(argv[0]);
142
- g_array_append_val(in_args, argument);
143
- }
144
- for (i = 0; i < n_args; i++) {
145
- GIArgInfo arg_info;
146
- g_callable_info_load_arg(callable_info, i, &arg_info);
147
- fill_argument(&arg_info, in_args, out_args, argc, argv);
542
+ arguments_init(&in_args, &out_args, &args_metadata);
543
+ if (receiver) {
544
+ g_array_append_val(in_args, *receiver);
148
545
  }
546
+ arguments_from_ruby(callable_info,
547
+ argc, argv,
548
+ in_args, out_args, args_metadata);
149
549
  succeeded = g_function_info_invoke(info,
150
550
  (GIArgument *)(in_args->data),
151
551
  in_args->len,
@@ -153,11 +553,17 @@ rb_gi_function_info_invoke_raw(GIFunctionInfo *info, int argc, VALUE *argv,
153
553
  out_args->len,
154
554
  return_value,
155
555
  &error);
156
- g_array_unref(in_args);
157
- g_array_unref(out_args);
556
+ if (succeeded) {
557
+ rb_out_args = out_arguments_to_ruby(callable_info,
558
+ in_args, out_args,
559
+ args_metadata);
560
+ }
561
+ arguments_free(in_args, out_args, args_metadata);
158
562
  if (!succeeded) {
159
563
  RG_RAISE_ERROR(error);
160
564
  }
565
+
566
+ return rb_out_args;
161
567
  }
162
568
 
163
569
  static VALUE
@@ -166,26 +572,38 @@ rg_invoke(int argc, VALUE *argv, VALUE self)
166
572
  GIFunctionInfo *info;
167
573
  GICallableInfo *callable_info;
168
574
  GIArgument return_value;
169
- GITypeInfo return_value_info;
575
+ VALUE rb_out_args;
576
+ VALUE rb_return_value;
170
577
 
171
578
  info = SELF(self);
172
- callable_info = (GICallableInfo *)info;
579
+ /* TODO: use rb_protect() */
580
+ rb_out_args = rb_gi_function_info_invoke_raw(info, NULL, argc, argv,
581
+ &return_value);
173
582
 
174
- rb_gi_function_info_invoke_raw(info, argc, argv, &return_value);
175
- g_callable_info_load_return_type(callable_info, &return_value_info);
583
+ callable_info = (GICallableInfo *)info;
584
+ rb_return_value = GI_RETURN_ARGUMENT2RVAL(&return_value, callable_info);
176
585
 
177
- return GI_ARGUMENT2RVAL(&return_value, &return_value_info);
586
+ if (NIL_P(rb_out_args)) {
587
+ return rb_return_value;
588
+ } else {
589
+ GITypeInfo return_value_info;
590
+ g_callable_info_load_return_type(callable_info, &return_value_info);
591
+ if (g_type_info_get_tag(&return_value_info) != GI_TYPE_TAG_VOID) {
592
+ rb_ary_unshift(rb_out_args, rb_return_value);
593
+ }
594
+ return rb_out_args;
595
+ }
178
596
  }
179
597
 
180
598
  void
181
599
  rb_gi_function_info_init(VALUE rb_mGI, VALUE rb_cGICallableInfo)
182
600
  {
183
- VALUE RG_TARGET_NAMESPACE;
184
-
185
601
  RG_TARGET_NAMESPACE =
186
602
  G_DEF_CLASS_WITH_PARENT(GI_TYPE_FUNCTION_INFO, "FunctionInfo", rb_mGI,
187
603
  rb_cGICallableInfo);
188
604
 
605
+ rb_iv_set(RG_TARGET_NAMESPACE, callbacks_key, rb_hash_new());
606
+
189
607
  RG_DEF_METHOD(symbol, 0);
190
608
  RG_DEF_METHOD(flags, 0);
191
609
  RG_DEF_METHOD(property, 0);