gir_ffi 0.10.2 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +13 -0
  3. data/Gemfile +9 -4
  4. data/README.md +3 -2
  5. data/Rakefile +2 -1
  6. data/lib/ffi-glib/byte_array.rb +1 -1
  7. data/lib/ffi-glib/main_loop.rb +2 -1
  8. data/lib/ffi-glib/strv.rb +5 -2
  9. data/lib/ffi-glib/variant.rb +3 -5
  10. data/lib/ffi-glib.rb +4 -0
  11. data/lib/ffi-gobject/closure.rb +8 -10
  12. data/lib/ffi-gobject/object.rb +9 -6
  13. data/lib/ffi-gobject/param_spec.rb +4 -0
  14. data/lib/ffi-gobject/value.rb +13 -16
  15. data/lib/ffi-gobject_introspection/gobject_type_init.rb +18 -0
  16. data/lib/ffi-gobject_introspection/i_callable_info.rb +1 -5
  17. data/lib/ffi-gobject_introspection/i_constant_info.rb +3 -3
  18. data/lib/ffi-gobject_introspection/i_repository.rb +3 -47
  19. data/lib/ffi-gobject_introspection/i_vfunc_info.rb +3 -11
  20. data/lib/ffi-gobject_introspection/lib.rb +8 -31
  21. data/lib/{gir_ffi-base/glib → ffi-gobject_introspection}/strv.rb +9 -13
  22. data/lib/ffi-gobject_introspection.rb +47 -2
  23. data/lib/gir_ffi/allocation_helper.rb +1 -19
  24. data/lib/gir_ffi/arg_helper.rb +36 -26
  25. data/lib/{gir_ffi-base/glib → gir_ffi}/boolean.rb +7 -5
  26. data/lib/gir_ffi/boxed_base.rb +5 -23
  27. data/lib/gir_ffi/builder.rb +3 -3
  28. data/lib/gir_ffi/builders/argument_builder.rb +7 -8
  29. data/lib/gir_ffi/builders/base_argument_builder.rb +0 -1
  30. data/lib/gir_ffi/builders/callback_argument_builder.rb +2 -2
  31. data/lib/gir_ffi/builders/callback_return_value_builder.rb +21 -13
  32. data/lib/gir_ffi/builders/field_builder.rb +4 -10
  33. data/lib/gir_ffi/builders/module_builder.rb +6 -4
  34. data/lib/gir_ffi/builders/object_builder.rb +16 -16
  35. data/lib/gir_ffi/builders/struct_builder.rb +4 -6
  36. data/lib/gir_ffi/builders/struct_like.rb +1 -1
  37. data/lib/gir_ffi/builders/user_defined_builder.rb +83 -23
  38. data/lib/gir_ffi/builders/vfunc_argument_builder.rb +12 -17
  39. data/lib/gir_ffi/class_base.rb +0 -4
  40. data/lib/gir_ffi/core.rb +16 -13
  41. data/lib/gir_ffi/enum_base.rb +2 -41
  42. data/lib/gir_ffi/enum_like_base.rb +48 -0
  43. data/lib/gir_ffi/ffi_ext/pointer.rb +1 -1
  44. data/lib/gir_ffi/flags_base.rb +2 -41
  45. data/lib/gir_ffi/in_out_pointer.rb +1 -1
  46. data/lib/gir_ffi/in_pointer.rb +4 -4
  47. data/lib/gir_ffi/info_ext/i_type_info.rb +14 -5
  48. data/lib/gir_ffi/info_ext/i_vfunc_info.rb +8 -0
  49. data/lib/gir_ffi/module_base.rb +4 -0
  50. data/lib/gir_ffi/receiver_argument_info.rb +1 -1
  51. data/lib/gir_ffi/sized_array.rb +6 -6
  52. data/lib/gir_ffi/struct_base.rb +1 -6
  53. data/lib/gir_ffi/struct_like_base.rb +54 -45
  54. data/lib/gir_ffi/type_map.rb +6 -7
  55. data/lib/gir_ffi/union_base.rb +1 -1
  56. data/lib/gir_ffi/{user_defined_type_info.rb → user_defined_object_info.rb} +1 -2
  57. data/lib/gir_ffi/user_defined_property_info.rb +80 -2
  58. data/lib/gir_ffi/version.rb +1 -1
  59. data/lib/gir_ffi-base/gobject/lib.rb +0 -1
  60. data/lib/gir_ffi-base/gobject.rb +3 -5
  61. data/lib/gir_ffi-base.rb +3 -8
  62. data/tasks/test.rake +17 -3
  63. data/test/base_test_helper.rb +39 -23
  64. data/test/ffi-glib/closure_test.rb +37 -0
  65. data/test/ffi-glib/main_loop_test.rb +24 -0
  66. data/test/ffi-glib/ruby_closure_test.rb +0 -5
  67. data/test/ffi-gobject/object_test.rb +6 -10
  68. data/test/ffi-gobject/param_spec_test.rb +17 -5
  69. data/test/ffi-gobject/value_test.rb +15 -6
  70. data/test/ffi-gobject_introspection/gobject_type_init_test.rb +25 -0
  71. data/test/ffi-gobject_introspection/i_base_info_test.rb +1 -1
  72. data/test/ffi-gobject_introspection/i_repository_test.rb +18 -0
  73. data/test/ffi-gobject_introspection/i_vfunc_info_test.rb +40 -0
  74. data/test/{gir_ffi-base/glib → ffi-gobject_introspection}/strv_test.rb +8 -8
  75. data/test/gir_ffi/allocation_helper_test.rb +35 -0
  76. data/test/gir_ffi/arg_helper_test.rb +102 -7
  77. data/test/gir_ffi/boolean_test.rb +34 -0
  78. data/test/gir_ffi/boxed_base_test.rb +46 -6
  79. data/test/gir_ffi/builder_test.rb +88 -29
  80. data/test/gir_ffi/builders/argument_builder_test.rb +19 -0
  81. data/test/gir_ffi/builders/callback_argument_builder_test.rb +17 -0
  82. data/test/gir_ffi/builders/callback_return_value_builder_test.rb +1 -1
  83. data/test/gir_ffi/builders/field_builder_test.rb +2 -1
  84. data/test/gir_ffi/builders/struct_builder_test.rb +42 -25
  85. data/test/gir_ffi/builders/user_defined_builder_test.rb +365 -17
  86. data/test/gir_ffi/builders/vfunc_argument_builder_test.rb +100 -0
  87. data/test/gir_ffi/builders/vfunc_builder_test.rb +5 -3
  88. data/test/{gir_ffi_test.rb → gir_ffi/core_test.rb} +8 -6
  89. data/test/gir_ffi/in_out_pointer_test.rb +1 -1
  90. data/test/gir_ffi/receiver_argument_info_test.rb +32 -0
  91. data/test/gir_ffi/sized_array_test.rb +34 -0
  92. data/test/gir_ffi/struct_base_test.rb +4 -32
  93. data/test/gir_ffi/struct_like_base_test.rb +164 -0
  94. data/test/gir_ffi/union_base_test.rb +4 -20
  95. data/test/gir_ffi/{user_defined_type_info_test.rb → user_defined_object_info_test.rb} +10 -10
  96. data/test/gir_ffi/user_defined_property_info_test.rb +22 -5
  97. data/test/gir_ffi/version_test.rb +1 -1
  98. data/test/integration/callback_exceptions_test.rb +2 -0
  99. data/test/integration/derived_classes_test.rb +2 -0
  100. data/test/integration/generated_everything_test.rb +22 -0
  101. data/test/integration/generated_gimarshallingtests_test.rb +23 -21
  102. data/test/integration/generated_gio_test.rb +2 -0
  103. data/test/integration/generated_glib_test.rb +2 -0
  104. data/test/integration/generated_gst_test.rb +2 -0
  105. data/test/integration/generated_gtop_test.rb +2 -0
  106. data/test/integration/generated_regress_test.rb +113 -29
  107. data/test/integration/generated_secret_test.rb +2 -0
  108. data/test/integration/generated_warnlib_test.rb +2 -0
  109. data/test/integration/method_lookup_test.rb +2 -0
  110. data/test/introspection_test_helper.rb +15 -0
  111. metadata +21 -27
  112. data/lib/gir_ffi-base/glib.rb +0 -8
  113. data/test/gir_ffi-base/glib/boolean_test.rb +0 -34
@@ -10,45 +10,28 @@ module GirFFI
10
10
  module ArgHelper
11
11
  OBJECT_STORE = ObjectStore.new
12
12
 
13
- def self.ptr_to_utf8_length(ptr, len)
14
- ptr.null? ? nil : ptr.read_string(len)
15
- end
16
-
17
13
  def self.check_error(errpp)
18
14
  err = GLib::Error.wrap(errpp.read_pointer)
19
15
  raise GLibError, err if err
20
16
  end
21
17
 
22
18
  def self.check_fixed_array_size(size, arr, name)
23
- unless arr.size == size
19
+ unless arr.size.equal? size
24
20
  raise ArgumentError, "#{name} should have size #{size}"
25
21
  end
26
22
  end
27
23
 
28
- def self.cast_from_pointer(type, it)
24
+ # NOTE: Only used in List, SList and HashTable classes.
25
+ # TODO: Stop using basic types and instead cast type to an ITypeInfo
26
+ # look-alike.
27
+ def self.cast_from_pointer(type, ptr)
29
28
  case type
30
- when :utf8, :filename
31
- it.to_utf8
32
- when :gint32, :gint8
33
- cast_pointer_to_int32 it
29
+ when Symbol
30
+ cast_from_simple_type_pointer(type, ptr)
34
31
  when Class
35
- type.wrap it
36
- when :guint32
37
- it.address
32
+ type.wrap ptr
38
33
  when Array
39
- main_type, subtype = *type
40
- raise "Unexpected main type #{main_type}" if main_type != :pointer
41
- case subtype
42
- when Array
43
- container_type, *element_type = *subtype
44
- raise "Unexpected container type #{container_type}" if container_type != :ghash
45
- GLib::HashTable.wrap(element_type, it)
46
- else
47
- raise "Unexpected subtype #{subtype}"
48
- end
49
-
50
- else
51
- raise "Don't know how to cast #{type}"
34
+ cast_from_complex_type_pointer(type, ptr)
52
35
  end
53
36
  end
54
37
 
@@ -67,5 +50,32 @@ module GirFFI
67
50
  def self.store(obj)
68
51
  OBJECT_STORE.store(obj)
69
52
  end
53
+
54
+ def self.cast_from_simple_type_pointer(type, ptr)
55
+ case type
56
+ when :utf8, :filename
57
+ ptr.to_utf8
58
+ when :gint32, :gint8
59
+ cast_pointer_to_int32 ptr
60
+ when :guint32
61
+ ptr.address
62
+ else
63
+ raise "Don't know how to cast #{type}"
64
+ end
65
+ end
66
+
67
+ def self.cast_from_complex_type_pointer(type, ptr)
68
+ main_type, (container_type, *element_type) = *type
69
+ case main_type
70
+ when :pointer
71
+ case container_type
72
+ when :ghash
73
+ return GLib::HashTable.wrap(element_type, ptr)
74
+ end
75
+ end
76
+ raise "Don't know how to cast #{type}"
77
+ end
78
+
79
+ private_class_method :cast_from_complex_type_pointer, :cast_from_simple_type_pointer
70
80
  end
71
81
  end
@@ -1,19 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
  require 'ffi'
3
- require 'gir_ffi-base/glib'
4
3
 
5
- module GLib
6
- # Implementation of gboolean
4
+ module GirFFI
5
+ # Class representing a boolean (natively, an int).
7
6
  class Boolean
8
7
  extend FFI::DataConverter
9
8
  native_type FFI::Type::INT
10
9
 
10
+ FROM_NATIVE = { 0 => false, 1 => true }.freeze
11
+ TO_NATIVE = FROM_NATIVE.invert
12
+
11
13
  def self.from_native(value, _context)
12
- value != 0 ? true : false
14
+ FROM_NATIVE.fetch(value)
13
15
  end
14
16
 
15
17
  def self.to_native(value, _context)
16
- value ? 1 : 0
18
+ TO_NATIVE.fetch(value)
17
19
  end
18
20
 
19
21
  def self.size
@@ -5,50 +5,32 @@ module GirFFI
5
5
  # Base class for generated classes representing boxed types.
6
6
  class BoxedBase < StructBase
7
7
  def initialize
8
- store_pointer(self.class::Struct.new.to_ptr)
8
+ store_pointer(nil)
9
9
  end
10
10
 
11
- def self.make_finalizer(struct, gtype)
11
+ def self.make_finalizer(struct)
12
12
  proc do
13
13
  if struct.owned?
14
- struct.owned = false
14
+ struct.owned = nil
15
15
  GObject.boxed_free gtype, struct.to_ptr
16
16
  end
17
17
  end
18
18
  end
19
19
 
20
- # Wrap value and take ownership of it
21
- def self.wrap_own(val)
22
- wrap(val).tap { |it| it && it.struct.owned = true }
23
- end
24
-
25
- # Create an unowned copy of the struct represented by val
26
- def self.copy_from(val)
27
- copy from(val)
28
- end
29
-
30
- # Wrap an owned copy of the struct represented by val
31
- def self.wrap_copy(val)
32
- # TODO: Is this needed? We may get away with just copying on transfer away from us.
33
- copy(wrap(val)).tap { |it| it && it.struct.owned = true }
34
- end
35
-
36
20
  def self.copy(val)
37
- return unless val
38
21
  ptr = GObject.boxed_copy(gtype, val)
39
22
  wrap(ptr)
40
23
  end
41
24
 
42
25
  private
43
26
 
44
- def store_pointer(ptr)
27
+ def store_pointer(*)
45
28
  super
46
29
  make_finalizer
47
30
  end
48
31
 
49
32
  def make_finalizer
50
- gtype = self.class.gtype
51
- ObjectSpace.define_finalizer self, self.class.make_finalizer(@struct, gtype)
33
+ ObjectSpace.define_finalizer self, self.class.make_finalizer(struct)
52
34
  end
53
35
  end
54
36
  end
@@ -29,9 +29,9 @@ module GirFFI
29
29
  end
30
30
 
31
31
  def self.build_module(namespace, version = nil)
32
- module_name = namespace.gsub(/^./, &:upcase)
33
- if Kernel.const_defined? module_name
34
- modul = Kernel.const_get module_name
32
+ module_name = namespace.sub(/\A./, &:upcase)
33
+ if const_defined? module_name
34
+ modul = const_get module_name
35
35
  unless modul.const_defined? :GIR_FFI_BUILDER
36
36
  raise "The module #{module_name} was already defined elsewhere"
37
37
  end
@@ -14,7 +14,6 @@ module GirFFI
14
14
  name if has_input_value? && !helper_argument?
15
15
  end
16
16
 
17
- # TODO: Improve this so each method can only have one block argument.
18
17
  def block_argument?
19
18
  specialized_type_tag == :callback
20
19
  end
@@ -90,7 +89,7 @@ module GirFFI
90
89
  base = pointer_to_value_method_call call_argument_name, type_spec
91
90
  if needs_out_conversion?
92
91
  outgoing_convertor(base).conversion
93
- elsif allocated_by_them?
92
+ elsif allocated_by_them? && specialized_type_tag != :void
94
93
  pointer_to_value_method_call base, sub_type_spec
95
94
  else
96
95
  base
@@ -98,7 +97,7 @@ module GirFFI
98
97
  end
99
98
 
100
99
  def outgoing_convertor(base)
101
- FullCToRubyConvertor.new(@type_info, base, length_argument_name,
100
+ FullCToRubyConvertor.new(type_info, base, length_argument_name,
102
101
  ownership_transfer: @arginfo.ownership_transfer)
103
102
  end
104
103
 
@@ -111,11 +110,11 @@ module GirFFI
111
110
  end
112
111
 
113
112
  def needs_out_conversion?
114
- @type_info.needs_c_to_ruby_conversion_for_functions?
113
+ type_info.needs_c_to_ruby_conversion_for_functions?
115
114
  end
116
115
 
117
116
  def gvalue?
118
- @type_info.gvalue?
117
+ type_info.gvalue?
119
118
  end
120
119
 
121
120
  # Check if an out argument needs to be allocated by them, the callee. Since
@@ -123,7 +122,7 @@ module GirFFI
123
122
  # is a pointer. For example, an out parameter of type gint8* will always
124
123
  # be allocated by the caller (that's us).
125
124
  def allocated_by_them?
126
- !@arginfo.caller_allocates? && @type_info.pointer?
125
+ !@arginfo.caller_allocates? && type_info.pointer?
127
126
  end
128
127
 
129
128
  def length_argument_name
@@ -197,8 +196,8 @@ module GirFFI
197
196
  NullConvertor.new(DESTROY_NOTIFIER)
198
197
  elsif closure?
199
198
  ClosureToPointerConvertor.new(pre_convertor_argument, @is_closure)
200
- elsif @type_info.needs_ruby_to_c_conversion_for_functions?
201
- RubyToCConvertor.new(@type_info, pre_convertor_argument,
199
+ elsif type_info.needs_ruby_to_c_conversion_for_functions?
200
+ RubyToCConvertor.new(type_info, pre_convertor_argument,
202
201
  ownership_transfer: ownership_transfer)
203
202
  else
204
203
  NullConvertor.new(pre_convertor_argument)
@@ -38,7 +38,6 @@ module GirFFI
38
38
  end
39
39
 
40
40
  def specialized_type_tag
41
- # SMELL: Law of Demeter, due to this being arginfo.argument_type.flattened_tag
42
41
  type_info.flattened_tag
43
42
  end
44
43
 
@@ -144,8 +144,8 @@ module GirFFI
144
144
 
145
145
  def out_parameter_preparation
146
146
  value = if allocated_by_us?
147
- ffi_type = TypeMap.type_specification_to_ffi_type type_spec[1]
148
- "GirFFI::AllocationHelper.allocate(#{ffi_type.inspect})" \
147
+ ffi_type = TypeMap.type_specification_to_ffi_type type_spec.last
148
+ "FFI::MemoryPointer.new(#{ffi_type.inspect})" \
149
149
  ".tap { |ptr| #{method_argument_name}.put_pointer 0, ptr }"
150
150
  else
151
151
  method_argument_name
@@ -9,16 +9,14 @@ module GirFFI
9
9
  class CallbackReturnValueBuilder < BaseReturnValueBuilder
10
10
  def post_conversion
11
11
  if has_post_conversion?
12
- if type_info.flattened_tag == :object
13
- ["#{post_converted_name} = #{post_convertor.conversion}.to_ptr"]
14
- else
15
- ["#{post_converted_name} = #{post_convertor.conversion}"]
16
- end
12
+ optional_outgoing_ref + base_post_conversion
17
13
  else
18
14
  []
19
15
  end
20
16
  end
21
17
 
18
+ private
19
+
22
20
  def has_post_conversion?
23
21
  relevant? && needs_ruby_to_c_conversion?
24
22
  end
@@ -27,19 +25,29 @@ module GirFFI
27
25
  type_info.needs_ruby_to_c_conversion_for_callbacks?
28
26
  end
29
27
 
30
- private
31
-
32
- def post_convertor
33
- @post_convertor ||= RubyToCConvertor.new(type_info, post_convertor_argument)
28
+ def optional_outgoing_ref
29
+ if outgoing_ref_needed?
30
+ ["#{capture_variable_name}.ref"]
31
+ else
32
+ []
33
+ end
34
34
  end
35
35
 
36
- def post_convertor_argument
37
- if ownership_transfer == :everything && specialized_type_tag == :object
38
- "#{capture_variable_name}.ref"
36
+ def base_post_conversion
37
+ if specialized_type_tag == :object
38
+ ["#{post_converted_name} = #{post_convertor.conversion}.to_ptr"]
39
39
  else
40
- capture_variable_name
40
+ ["#{post_converted_name} = #{post_convertor.conversion}"]
41
41
  end
42
42
  end
43
+
44
+ def post_convertor
45
+ @post_convertor ||= RubyToCConvertor.new(type_info, capture_variable_name)
46
+ end
47
+
48
+ def outgoing_ref_needed?
49
+ ownership_transfer == :everything && specialized_type_tag == :object
50
+ end
43
51
  end
44
52
  end
45
53
  end
@@ -229,8 +229,9 @@ module GirFFI
229
229
 
230
230
  attr_reader :info
231
231
 
232
- def initialize(field_info)
232
+ def initialize(field_info, container_class)
233
233
  @info = field_info
234
+ @container_class = container_class
234
235
  end
235
236
 
236
237
  def build
@@ -285,13 +286,7 @@ module GirFFI
285
286
  @field_type_tag ||= field_type.tag_or_class
286
287
  end
287
288
 
288
- def container_class
289
- @container_class ||= container_module.const_get(container_info.safe_name)
290
- end
291
-
292
- def container_module
293
- @container_module ||= Object.const_get(container_info.safe_namespace)
294
- end
289
+ attr_reader :container_class
295
290
 
296
291
  def container_info
297
292
  @container_info ||= info.container
@@ -310,9 +305,8 @@ module GirFFI
310
305
  field_argument_info)
311
306
  end
312
307
 
313
- # rubocop:disable Style/ZeroLengthPredicate
314
308
  def hidden_struct_type?
315
- field_type.flattened_tag == :struct && field_type.interface.size == 0
309
+ field_type.hidden_struct_type?
316
310
  end
317
311
  end
318
312
  end
@@ -32,6 +32,10 @@ module GirFFI
32
32
  true
33
33
  end
34
34
 
35
+ def method_available?(method)
36
+ function_introspection_data(method.to_s) and true
37
+ end
38
+
35
39
  def build_namespaced_class(classname)
36
40
  info = find_namespaced_class_info(classname)
37
41
  Builder.build_class info
@@ -109,11 +113,9 @@ module GirFFI
109
113
  end
110
114
 
111
115
  def gir
112
- unless defined? @gir
113
- @gir = GObjectIntrospection::IRepository.default
114
- @gir.require @namespace, @version
116
+ @gir ||= GObjectIntrospection::IRepository.default.tap do |it|
117
+ it.require @namespace, @version
115
118
  end
116
- @gir
117
119
  end
118
120
  end
119
121
  end
@@ -79,12 +79,7 @@ module GirFFI
79
79
  end
80
80
 
81
81
  def parent_info
82
- unless defined? @parent_info
83
- @parent_info = if (parent = info.parent) && parent != info
84
- parent
85
- end
86
- end
87
- @parent_info
82
+ info.parent
88
83
  end
89
84
 
90
85
  def superclass
@@ -105,7 +100,7 @@ module GirFFI
105
100
 
106
101
  def setup_field_accessors
107
102
  eligible_fields.each do |finfo|
108
- FieldBuilder.new(finfo).build
103
+ FieldBuilder.new(finfo, klass).build
109
104
  end
110
105
  end
111
106
 
@@ -119,9 +114,7 @@ module GirFFI
119
114
  # TODO: Create object responsible for creating these invokers
120
115
  def setup_vfunc_invokers
121
116
  info.vfuncs.each do |vfinfo|
122
- if (invoker = vfinfo.invoker)
123
- define_vfunc_invoker vfinfo.name, invoker.name
124
- end
117
+ define_vfunc_invoker vfinfo.name, vfinfo.invoker_name if vfinfo.has_invoker?
125
118
  end
126
119
  end
127
120
 
@@ -137,12 +130,19 @@ module GirFFI
137
130
  def provide_initializer
138
131
  return if info.find_method 'new'
139
132
 
140
- # FIXME: Only valid if the object descends from GObject::Object
141
- klass.class_eval "
142
- def initialize(properties = {})
143
- base_initialize(properties)
144
- end
145
- "
133
+ if info.abstract?
134
+ klass.class_eval <<-END
135
+ def initialize(*)
136
+ raise NoMethodError
137
+ end
138
+ END
139
+ else
140
+ klass.class_eval <<-END
141
+ def initialize(properties = {})
142
+ base_initialize(properties)
143
+ end
144
+ END
145
+ end
146
146
  end
147
147
 
148
148
  def setup_interfaces
@@ -16,12 +16,10 @@ module GirFFI
16
16
  def superclass
17
17
  if info.gtype_struct?
18
18
  # HACK: Inheritance chain is not expressed in GObject's code correctly.
19
- if info.full_type_name == 'GObject::InitiallyUnownedClass'
20
- return GObject::ObjectClass
21
- else
22
- type = fields.first.field_type
23
- return type.tag_or_class if type.tag == :interface
24
- end
19
+ type_name = info.full_type_name
20
+ return GObject::ObjectClass if type_name == 'GObject::InitiallyUnownedClass'
21
+ type = fields.first.field_type
22
+ return type.tag_or_class if type.tag == :interface
25
23
  end
26
24
 
27
25
  if GObject.type_fundamental(info.gtype) == GObject::TYPE_BOXED
@@ -16,7 +16,7 @@ module GirFFI
16
16
 
17
17
  def setup_field_accessors
18
18
  fields.each do |finfo|
19
- FieldBuilder.new(finfo).build
19
+ FieldBuilder.new(finfo, klass).build
20
20
  end
21
21
  end
22
22
  end
@@ -11,8 +11,8 @@ module GirFFI
11
11
  end
12
12
 
13
13
  def setup_class
14
- register_type
15
14
  setup_layout
15
+ register_type
16
16
  setup_constants
17
17
  setup_property_accessors
18
18
  setup_constructor
@@ -86,8 +86,10 @@ module GirFFI
86
86
 
87
87
  def instance_size
88
88
  size = parent_gtype.instance_size
89
- properties.each do
90
- size += FFI.type_size(:int32)
89
+ alignment = struct_class.alignment
90
+ properties.each do |prop|
91
+ type_size = FFI.type_size(prop.ffi_type)
92
+ size += [type_size, alignment].max
91
93
  end
92
94
  size
93
95
  end
@@ -109,13 +111,13 @@ module GirFFI
109
111
 
110
112
  def property_getter
111
113
  proc do |object, _property_id, value, pspec|
112
- value.set_value object.send(pspec.get_name)
114
+ value.set_value object.send(pspec.accessor_name)
113
115
  end
114
116
  end
115
117
 
116
118
  def property_setter
117
119
  proc do |object, _property_id, value, pspec|
118
- object.send("#{pspec.get_name}=", value.get_value)
120
+ object.send("#{pspec.accessor_name}=", value.get_value)
119
121
  end
120
122
  end
121
123
 
@@ -167,34 +169,92 @@ module GirFFI
167
169
  end
168
170
 
169
171
  def layout_specification
170
- parent_spec = [:parent, superclass::Struct, 0]
171
- offset = superclass::Struct.size
172
- fields_spec = properties.flat_map do |pinfo|
173
- spec = [pinfo.name.to_sym, :int32, offset]
174
- offset += FFI.type_size(:int32)
172
+ parent_spec = [:parent, superclass::Struct]
173
+ offset = parent_gtype.instance_size
174
+
175
+ alignment = superclass::Struct.alignment
176
+ fields_spec = properties.flat_map do |param_info|
177
+ field_name = param_info.accessor_name
178
+ ffi_type = param_info.ffi_type
179
+ type_size = FFI.type_size(ffi_type)
180
+ spec = [field_name, ffi_type, offset]
181
+ offset += [type_size, alignment].max
175
182
  spec
176
183
  end
177
184
  parent_spec + fields_spec
178
185
  end
179
186
 
180
- def setup_property_accessors
181
- properties.each do |pinfo|
182
- setup_accessors_for_param_info pinfo
187
+ # TODO: Move this to its own file.
188
+ # TODO: See if this or FieldTypeInfo can be merged with with
189
+ # UserDefinedPropertyInfo.
190
+ class UserDefinedPropertyFieldInfo
191
+ # Field info for user-defined property
192
+ class FieldTypeInfo
193
+ include InfoExt::ITypeInfo
194
+
195
+ def initialize(property_info)
196
+ @property_info = property_info
197
+ end
198
+
199
+ def tag
200
+ @property_info.type_tag
201
+ end
202
+
203
+ def pointer?
204
+ @property_info.pointer_type?
205
+ end
206
+
207
+ def interface_type
208
+ @property_info.interface_type_tag if tag == :interface
209
+ end
210
+
211
+ def hidden_struct_type?
212
+ false
213
+ end
214
+
215
+ def interface_class
216
+ Builder.build_by_gtype @property_info.value_type if tag == :interface
217
+ end
218
+
219
+ def interface_class_name
220
+ interface_class.name if tag == :interface
221
+ end
183
222
  end
184
- end
185
223
 
186
- def setup_accessors_for_param_info(pinfo)
187
- field_name = pinfo.name
188
- code = <<-CODE
189
- def #{field_name}
190
- @struct[:#{field_name}]
224
+ def initialize(property_info, container, offset)
225
+ @property_info = property_info
226
+ @container = container
227
+ @offset = offset
191
228
  end
192
- def #{field_name}= val
193
- @struct[:#{field_name}] = val
229
+
230
+ attr_reader :container, :offset
231
+
232
+ def name
233
+ @property_info.accessor_name
194
234
  end
195
- CODE
196
235
 
197
- klass.class_eval code
236
+ def field_type
237
+ @field_type ||= FieldTypeInfo.new @property_info
238
+ end
239
+
240
+ def related_array_length_field
241
+ nil
242
+ end
243
+
244
+ def writable?
245
+ @property_info.writable?
246
+ end
247
+ end
248
+
249
+ def setup_property_accessors
250
+ offset = parent_gtype.instance_size
251
+ alignment = struct_class.alignment
252
+ properties.each do |param_info|
253
+ field_info = UserDefinedPropertyFieldInfo.new(param_info, info, offset)
254
+ type_size = FFI.type_size(param_info.ffi_type)
255
+ offset += [type_size, alignment].max
256
+ FieldBuilder.new(field_info, klass).build
257
+ end
198
258
  end
199
259
 
200
260
  def method_introspection_data(_method)
@@ -7,8 +7,16 @@ module GirFFI
7
7
  # argument mapper for vfuncs.
8
8
  class VFuncArgumentBuilder < CallbackArgumentBuilder
9
9
  def pre_conversion
10
- if ingoing_ref_needed
11
- super + [pre_ref_count_increase]
10
+ if ingoing_ref_needed?
11
+ super + ["#{pre_converted_name}.ref"]
12
+ else
13
+ super
14
+ end
15
+ end
16
+
17
+ def post_conversion
18
+ if outgoing_ref_needed?
19
+ ["#{result_name}.ref"] + super
12
20
  else
13
21
  super
14
22
  end
@@ -16,26 +24,13 @@ module GirFFI
16
24
 
17
25
  private
18
26
 
19
- def ingoing_ref_needed
27
+ def ingoing_ref_needed?
20
28
  direction == :in &&
21
29
  ownership_transfer == :nothing &&
22
30
  specialized_type_tag == :object
23
31
  end
24
32
 
25
- def pre_ref_count_increase
26
- "#{pre_converted_name}.ref"
27
- end
28
-
29
- # SMELL: Override private method
30
- def post_convertor_argument
31
- if outgoing_ref_needed
32
- "#{super}.ref"
33
- else
34
- super
35
- end
36
- end
37
-
38
- def outgoing_ref_needed
33
+ def outgoing_ref_needed?
39
34
  direction == :out &&
40
35
  ownership_transfer == :everything &&
41
36
  specialized_type_tag == :object
@@ -31,10 +31,6 @@ module GirFFI
31
31
  other.class == self.class && to_ptr.address == other.to_ptr.address
32
32
  end
33
33
 
34
- def initialize
35
- raise NoMethodError
36
- end
37
-
38
34
  def self.setup_and_call(method, arguments, &block)
39
35
  method_name = try_in_ancestors(:setup_method, method.to_s)
40
36