gobject-introspection 3.4.4 → 3.4.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -22,6 +22,7 @@
22
22
 
23
23
  #include <ruby.h>
24
24
  #include <rbgobject.h>
25
+ #include <rbglib2conversions.h>
25
26
  #include <glib-enum-types.h>
26
27
 
27
28
  #include <girffi.h>
@@ -1,6 +1,6 @@
1
1
  /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
2
  /*
3
- * Copyright (C) 2012-2019 Ruby-GNOME Project Team
3
+ * Copyright (C) 2012-2021 Ruby-GNOME 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
@@ -194,6 +194,17 @@ rg_get_field(VALUE self, VALUE rb_n)
194
194
  return GI_BASE_INFO2RVAL_WITH_UNREF(g_struct_info_get_field(info, n));
195
195
  }
196
196
 
197
+ static VALUE
198
+ rg_find_field(VALUE self, VALUE rb_name)
199
+ {
200
+ GIStructInfo *info;
201
+ const gchar *name;
202
+
203
+ info = SELF(self);
204
+ name = RVAL2CSTR(rb_name);
205
+ return GI_BASE_INFO2RVAL_WITH_UNREF(g_struct_info_find_field(info, name));
206
+ }
207
+
197
208
  static VALUE
198
209
  rg_get_field_value(VALUE self, VALUE rb_struct, VALUE rb_n)
199
210
  {
@@ -308,6 +319,7 @@ rb_gi_struct_info_init(VALUE rb_mGI, VALUE rb_cGIRegisteredTypeInfo)
308
319
 
309
320
  RG_DEF_METHOD(n_fields, 0);
310
321
  RG_DEF_METHOD(get_field, 1);
322
+ RG_DEF_METHOD(find_field, 1);
311
323
  RG_DEF_METHOD(get_field_value, 2);
312
324
  RG_DEF_METHOD(set_field_value, 3);
313
325
  RG_DEF_METHOD(n_methods, 0);
@@ -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-2021 Ruby-GNOME 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
@@ -21,7 +21,7 @@
21
21
  #include "rb-gi-private.h"
22
22
 
23
23
  #define RG_TARGET_NAMESPACE rb_cGIVFuncInfo
24
- #define SELF(self) RVAL2GI_BASE_INFO(self)
24
+ #define SELF(self) RVAL2GI_VFUNC_INFO(self)
25
25
 
26
26
  GType
27
27
  gi_vfunc_info_get_type(void)
@@ -22,6 +22,15 @@
22
22
 
23
23
  #define RG_TARGET_NAMESPACE rb_mGObjectIntrospection
24
24
 
25
+ typedef struct {
26
+ ID name;
27
+ GICallableInfo *callable_info;
28
+
29
+ ffi_cif cif;
30
+ ffi_closure *closure;
31
+ } RBGIVFuncCallbackData;
32
+
33
+ static ID id_send;
25
34
  static gboolean is_debug_mode = FALSE;
26
35
 
27
36
  gboolean
@@ -30,11 +39,231 @@ rb_gi_is_debug_mode(void)
30
39
  return is_debug_mode;
31
40
  }
32
41
 
42
+ static void
43
+ find_vfunc_info (GIBaseInfo *vfunc_info,
44
+ GType implementor_gtype,
45
+ gpointer *implementor_vtable_ret,
46
+ GIFieldInfo **field_info_ret)
47
+ {
48
+ GIBaseInfo *ancestor_info = NULL;
49
+ GIStructInfo *struct_info = NULL;
50
+ GIFieldInfo *field_info = NULL;
51
+
52
+ ancestor_info = g_base_info_get_container(vfunc_info);
53
+ // ancestor_gtype = g_registered_type_info_get_g_type (
54
+ // (GIRegisteredTypeInfo *) ancestor_info);
55
+ struct_info = g_object_info_get_class_struct((GIObjectInfo*) ancestor_info);
56
+ *implementor_vtable_ret = g_type_class_ref(implementor_gtype);
57
+
58
+ field_info = g_struct_info_find_field(
59
+ struct_info, g_base_info_get_name((GIBaseInfo*) vfunc_info));
60
+
61
+ if (field_info != NULL) {
62
+ GITypeInfo *type_info;
63
+
64
+ type_info = g_field_info_get_type (field_info);
65
+ if (g_type_info_get_tag (type_info) == GI_TYPE_TAG_INTERFACE) {
66
+ *field_info_ret = field_info;
67
+ } else {
68
+ g_base_info_unref (field_info);
69
+ }
70
+ g_base_info_unref (type_info);
71
+ }
72
+
73
+ g_base_info_unref (struct_info);
74
+ }
75
+
76
+ static VALUE
77
+ garg2rval(GIArgument *argument, GITypeTag type_tag)
78
+ {
79
+ switch (type_tag) {
80
+ case GI_TYPE_TAG_INT32:
81
+ return INT2FIX(argument->v_int32);
82
+ default:
83
+ rb_raise(rb_eTypeError, "garg2rval: not implemented");
84
+ break;
85
+ }
86
+ }
87
+
88
+ static void
89
+ rval2garg(VALUE value, GITypeTag type_tag, GIArgument *argument)
90
+ {
91
+ switch (type_tag) {
92
+ case GI_TYPE_TAG_INT32:
93
+ argument->v_int32 = FIX2INT(value);
94
+ break;
95
+ default:
96
+ rb_raise(rb_eTypeError, "rval2garg: not implemented");
97
+ break;
98
+ }
99
+ }
100
+
101
+ static void
102
+ rval2ffiarg(VALUE value, ffi_arg *arg)
103
+ {
104
+ switch (TYPE(value)) {
105
+ case T_NIL:
106
+ break;
107
+ case T_FIXNUM:
108
+ case T_DATA:
109
+ *arg = FIX2INT(value);
110
+ break;
111
+ default:
112
+ rb_raise(rb_eTypeError, "rval2ffiarg: not implemented");
113
+ break;
114
+ }
115
+ }
116
+
117
+ static void
118
+ ffi_callback(G_GNUC_UNUSED ffi_cif *cif,
119
+ void *ret,
120
+ void **raw_args,
121
+ void *raw_data)
122
+ {
123
+ GIArgument **args = NULL;
124
+ RBGIVFuncCallbackData *data = NULL;
125
+ GObject* receiver = NULL;
126
+ VALUE rb_receiver = 0;
127
+ gint n_args = 0, n_in_args = 0, n_out_args = 0;
128
+ size_t i = 0, j = 0;
129
+ VALUE *in_values = NULL;
130
+ VALUE rb_ret;
131
+ GIArgInfo arg_info;
132
+ GITypeInfo type_info;
133
+ GITypeTag type_tag;
134
+ GIDirection direction;
135
+ gboolean ret_type_is_void;
136
+
137
+ args = (GIArgument **) raw_args;
138
+ data = (RBGIVFuncCallbackData *) raw_data;
139
+
140
+ receiver = G_OBJECT(args[0]->v_pointer);
141
+ rb_receiver = GOBJ2RVAL(receiver);
142
+
143
+ n_args = g_callable_info_get_n_args(data->callable_info);
144
+ in_values = (VALUE *) malloc(n_args * sizeof(VALUE));
145
+ in_values[0] = data->name;
146
+ n_in_args++;
147
+
148
+ for (i = 1, j = 1; i < n_args; i++) {
149
+ g_callable_info_load_arg(data->callable_info, i, &arg_info);
150
+ g_arg_info_load_type(&arg_info, &type_info);
151
+ type_tag = g_type_info_get_tag(&type_info);
152
+ direction = g_arg_info_get_direction(&arg_info);
153
+
154
+ if (type_tag == GI_TYPE_TAG_VOID) continue;
155
+
156
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
157
+ n_out_args++;
158
+
159
+ if (direction == GI_DIRECTION_OUT) continue;
160
+
161
+ in_values[j] = garg2rval(args[i], type_tag);
162
+ j++; n_in_args++;
163
+ }
164
+
165
+ // result = rb_funcall(rb_receiver, id_send, 1, data->name);
166
+ rb_ret = rb_funcallv(rb_receiver, id_send, n_in_args, in_values);
167
+
168
+ g_callable_info_load_return_type(data->callable_info, &type_info);
169
+ ret_type_is_void = g_type_info_get_tag(&type_info) == GI_TYPE_TAG_VOID;
170
+
171
+ if (n_out_args == 0 && ret_type_is_void) {
172
+ // do nothing
173
+ } else if (n_out_args == 0) {
174
+ rval2ffiarg(rb_ret, ret);
175
+ } else if (n_out_args == 1 && ret_type_is_void) {
176
+ for (i = 1; i < n_args; i++) {
177
+ g_callable_info_load_arg(data->callable_info, i, &arg_info);
178
+ g_arg_info_load_type(&arg_info, &type_info);
179
+ type_tag = g_type_info_get_tag(&type_info);
180
+ direction = g_arg_info_get_direction(&arg_info);
181
+
182
+ if (type_tag == GI_TYPE_TAG_VOID || direction == GI_DIRECTION_IN)
183
+ continue;
184
+
185
+ rval2garg(rb_ret, type_tag, *(GIArgument **) args[i]);
186
+ break;
187
+ }
188
+ } else {
189
+ if (TYPE(rb_ret) != T_ARRAY) {
190
+ rb_raise(rb_eTypeError, "return type should be Array");
191
+ }
192
+
193
+ for (i = 1, j = 0; i < n_args; i++) {
194
+ g_callable_info_load_arg(data->callable_info, i, &arg_info);
195
+ g_arg_info_load_type(&arg_info, &type_info);
196
+ type_tag = g_type_info_get_tag(&type_info);
197
+ direction = g_arg_info_get_direction(&arg_info);
198
+
199
+ if (type_tag == GI_TYPE_TAG_VOID || direction == GI_DIRECTION_IN)
200
+ continue;
201
+
202
+ rval2garg(rb_ary_entry(rb_ret, j), type_tag, *(GIArgument **) args[i]);
203
+ j++;
204
+ }
205
+ }
206
+
207
+ free(in_values);
208
+ }
209
+
210
+ static VALUE
211
+ rb_gi_hook_up_vfunc(G_GNUC_UNUSED VALUE self,
212
+ VALUE rb_name,
213
+ VALUE rb_vfunc_info,
214
+ VALUE rb_gtype)
215
+ {
216
+ GIVFuncInfo *vfunc_info = NULL;
217
+ GType gtype = 0;
218
+ gpointer implementor_vtable = NULL;
219
+ GIFieldInfo *field_info = NULL;
220
+
221
+ vfunc_info = RVAL2GI_BASE_INFO(rb_vfunc_info);
222
+ gtype = NUM2LONG(rb_gtype);
223
+ g_assert(G_TYPE_IS_CLASSED(gtype));
224
+
225
+ find_vfunc_info(vfunc_info, gtype, &implementor_vtable, &field_info);
226
+
227
+ if (field_info != NULL) {
228
+ GITypeInfo *type_info = NULL;
229
+ GIBaseInfo *interface_info = NULL;
230
+ RBGIVFuncCallbackData *data = NULL;
231
+ gint offset = 0;
232
+ gpointer *method_ptr = NULL;
233
+
234
+ type_info = g_field_info_get_type(field_info);
235
+
236
+ interface_info = g_type_info_get_interface(type_info);
237
+ g_assert(g_base_info_get_type(interface_info) == GI_INFO_TYPE_CALLBACK);
238
+
239
+ data = ALLOC(RBGIVFuncCallbackData);
240
+ data->name = rb_name;
241
+ data->callable_info = g_base_info_ref(interface_info);
242
+ data->closure = g_callable_info_prepare_closure(
243
+ interface_info, &(data->cif), ffi_callback, data);
244
+
245
+ if (data->closure) {
246
+ offset = g_field_info_get_offset(field_info);
247
+ method_ptr = G_STRUCT_MEMBER_P(implementor_vtable, offset);
248
+
249
+ *method_ptr = data->closure;
250
+ }
251
+
252
+ g_base_info_unref (interface_info);
253
+ g_base_info_unref (type_info);
254
+ g_base_info_unref (field_info);
255
+ }
256
+
257
+ return Qnil;
258
+ }
259
+
33
260
  void
34
261
  Init_gobject_introspection(void)
35
262
  {
36
263
  VALUE RG_TARGET_NAMESPACE;
37
264
 
265
+ id_send = rb_intern("__send__");
266
+
38
267
  {
39
268
  const char *rb_gi_debug_env = getenv("RB_GI_DEBUG");
40
269
  if (rb_gi_debug_env && strcmp(rb_gi_debug_env, "yes") == 0) {
@@ -59,4 +288,6 @@ Init_gobject_introspection(void)
59
288
  rb_gi_loader_init(RG_TARGET_NAMESPACE);
60
289
 
61
290
  rb_gi_callback_init(RG_TARGET_NAMESPACE);
291
+
292
+ rb_define_module_function(RG_TARGET_NAMESPACE, "hook_up_vfunc", rb_gi_hook_up_vfunc, 3);
62
293
  }
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2012-2019 Ruby-GNOME Project Team
1
+ # Copyright (C) 2012-2021 Ruby-GNOME Project Team
2
2
  #
3
3
  # This library is free software; you can redistribute it and/or
4
4
  # modify it under the terms of the GNU Lesser General Public
@@ -216,6 +216,7 @@ module GObjectIntrospection
216
216
  klass = self.class.define_class(info.gtype,
217
217
  rubyish_class_name(info),
218
218
  @base_module)
219
+ load_virtual_functions(info, klass)
219
220
  load_fields(info, klass)
220
221
  load_methods(info, klass)
221
222
  end
@@ -338,6 +339,20 @@ module GObjectIntrospection
338
339
  end
339
340
  end
340
341
 
342
+ def load_virtual_functions(info, klass)
343
+ klass.extend(VirtualFunctionImplementable)
344
+ gtype_prefix = rubyish_gtype_name(klass.gtype.name)
345
+ implementor = VirtualFunctionImplementor.new(self.class,
346
+ gtype_prefix,
347
+ info.vfuncs)
348
+ klass.__send__(:initialize_virtual_function_implementable,
349
+ implementor)
350
+ end
351
+
352
+ def rubyish_gtype_name(name)
353
+ name.scan(/[A-Z]+[a-z\d]+/).collect(&:downcase).join("_")
354
+ end
355
+
341
356
  def initialize_post(object)
342
357
  end
343
358
 
@@ -546,6 +561,7 @@ module GObjectIntrospection
546
561
  self.class.define_interface(info.gtype,
547
562
  rubyish_class_name(info),
548
563
  @base_module)
564
+ load_virtual_functions(info, interface_module)
549
565
  load_methods(info, interface_module)
550
566
  end
551
567
 
@@ -708,5 +724,53 @@ module GObjectIntrospection
708
724
  "#{@full_method_name}: wrong number of arguments (#{detail})"
709
725
  end
710
726
  end
727
+
728
+ class VirtualFunctionImplementor
729
+ def initialize(loader_class, gtype_prefix, infos)
730
+ @loader_class = loader_class
731
+ @gtype_prefix = gtype_prefix
732
+ @infos = {}
733
+ prefix = GLib::VIRTUAL_FUNCTION_IMPLEMENTATION_PREFIX
734
+ infos.each do |info|
735
+ name = info.name
736
+ @infos[:"#{prefix}#{name}"] = info
737
+ @infos[:"#{prefix}#{gtype_prefix}_#{name}"] = info
738
+ end
739
+ end
740
+
741
+ def implement(implementor_gtype, name)
742
+ info = @infos[name]
743
+ return false if info.nil?
744
+ container = info.container
745
+ vtable_gtype = container.gtype
746
+ if container.respond_to?(:class_struct)
747
+ struct = container.class_struct
748
+ else
749
+ return false unless implementor_gtype.type_is_a?(vtable_gtype)
750
+ struct = container.iface_struct
751
+ end
752
+ field = struct.find_field(info.name)
753
+ @loader_class.implement_virtual_function(field,
754
+ implementor_gtype,
755
+ vtable_gtype,
756
+ name.to_s)
757
+ true
758
+ end
759
+ end
760
+
761
+ module VirtualFunctionImplementable
762
+ def initialize_virtual_function_implementable(implementor)
763
+ @virtual_function_implementor = implementor
764
+ end
765
+
766
+ def implement_virtual_function(implementor_class, name)
767
+ unless instance_variable_defined?(:@virtual_function_implementor)
768
+ return false
769
+ end
770
+ @virtual_function_implementor.implement(implementor_class.gtype,
771
+ name)
772
+ true
773
+ end
774
+ end
711
775
  end
712
776
  end
data/test/run-test.rb CHANGED
@@ -32,4 +32,8 @@ run_test(__dir__,
32
32
  puts("Omit because typelib file doesn't exist: #{$!.message}")
33
33
  exit(true)
34
34
  end
35
+
36
+ module Gio
37
+ GObjectIntrospection::Loader.load("Gio", self)
38
+ end
35
39
  end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2012 Ruby-GNOME2 Project Team
1
+ # Copyright (C) 2012-2021 Ruby-GNOME Project Team
2
2
  #
3
3
  # This library is free software; you can redistribute it and/or
4
4
  # modify it under the terms of the GNU Lesser General Public
@@ -28,4 +28,8 @@ class TestBaseInfo < Test::Unit::TestCase
28
28
  def test_namespace
29
29
  assert_equal("GObject", @info.namespace)
30
30
  end
31
+
32
+ def test_container
33
+ assert_equal("Object", @info.vfuncs.first.container.name)
34
+ end
31
35
  end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2012 Ruby-GNOME2 Project Team
1
+ # Copyright (C) 2012-2021 Ruby-GNOME Project Team
2
2
  #
3
3
  # This library is free software; you can redistribute it and/or
4
4
  # modify it under the terms of the GNU Lesser General Public
@@ -21,6 +21,12 @@ class TestCallableInfo < Test::Unit::TestCase
21
21
  @info = @repository.find("GObject", "signal_name")
22
22
  end
23
23
 
24
+ def test_can_throw_gerror
25
+ assert do
26
+ not @info.can_throw_gerror?
27
+ end
28
+ end
29
+
24
30
  def test_return_type
25
31
  assert_kind_of(GObjectIntrospection::TypeInfo,
26
32
  @info.return_type)