gir_ffi 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,11 @@
1
+ == 0.0.6 / 2011-03-01
2
+
3
+ * Cast returned GObjects to their actual type.
4
+ * Properly cast callback arguments.
5
+ * Handle the case where functions formally return interfaces.
6
+ * Make sure Gtk::Window has the correct number of references after creation.
7
+ * Refactoring and some small fixes.
8
+
1
9
  == 0.0.5 / 2010-12-30
2
10
 
3
11
  * Don't create instance methods out of functions and vice versa.
@@ -41,7 +41,7 @@ module GirFFI
41
41
  AllocationHelper.safe_malloc(len + 1).write_string(str).put_char(len, 0)
42
42
  end
43
43
 
44
- def self.GType_array_to_inptr ary
44
+ def self.gtype_array_to_inptr ary
45
45
  case FFI.type_size(:size_t)
46
46
  when 4
47
47
  int32_array_to_inptr ary
@@ -64,8 +64,6 @@ module GirFFI
64
64
 
65
65
  # Takes an outptr to a pointer array, and frees all pointers.
66
66
  def self.cleanup_ptr_array_ptr ptr, size
67
- return if ptr.nil?
68
-
69
67
  block = ptr.read_pointer
70
68
  LibC.free ptr
71
69
 
@@ -74,9 +72,7 @@ module GirFFI
74
72
  ptrs = block.read_array_of_pointer(size)
75
73
  LibC.free block
76
74
 
77
- ptrs.map do |p|
78
- LibC.free p unless p.null?
79
- end
75
+ ptrs.each { |ptr| LibC.free ptr }
80
76
  end
81
77
 
82
78
  def self.int_to_inoutptr val
@@ -148,22 +144,16 @@ module GirFFI
148
144
 
149
145
  # Converts an outptr to a string.
150
146
  def self.outptr_to_utf8 ptr
151
- return nil if ptr.nil?
152
- sptr = ptr.read_pointer
153
-
154
- sptr.null? ? nil : sptr.read_string
147
+ ptr_to_utf8 ptr.read_pointer
155
148
  end
156
149
 
157
150
  # Converts an outptr to a string array.
158
151
  def self.outptr_to_utf8_array ptr, size
159
- return nil if ptr.nil?
160
152
  block = ptr.read_pointer
161
153
  return nil if block.null?
162
154
  ptrs = block.read_array_of_pointer(size)
163
155
 
164
- ptrs.map do |p|
165
- p.null? ? nil : p.read_string
166
- end
156
+ ptrs.map { |ptr| ptr_to_utf8 ptr }
167
157
  end
168
158
 
169
159
  # Converts an outptr to a double.
@@ -173,7 +163,6 @@ module GirFFI
173
163
 
174
164
  # Converts an outptr to an array of int.
175
165
  def self.outptr_to_int_array ptr, size
176
- return nil if ptr.null?
177
166
  block = ptr.read_pointer
178
167
  return nil if block.null?
179
168
  ptr_to_int_array block, size
@@ -183,25 +172,50 @@ module GirFFI
183
172
  ptr.read_array_of_int(size)
184
173
  end
185
174
 
186
- def self.mapped_callback_args prc=nil, &block
175
+ def self.ptr_to_utf8 ptr
176
+ ptr.null? ? nil : ptr.read_string
177
+ end
178
+
179
+ def self.wrap_in_callback_args_mapper namespace, name, prc
187
180
  return prc if FFI::Function === prc
188
- if prc.nil?
189
- return nil if block.nil?
190
- prc = block
191
- end
181
+ return nil if prc.nil?
182
+ info = gir.find_by_name namespace, name
192
183
  return Proc.new do |*args|
193
- mapped = args.map {|arg|
194
- if FFI::Pointer === arg
195
- begin
196
- ObjectSpace._id2ref arg.address
197
- rescue RangeError
198
- arg
199
- end
200
- else
184
+ prc.call(*map_callback_args(args, info))
185
+ end
186
+ end
187
+
188
+ def self.map_callback_args args, info
189
+ args.zip(info.args).map { |arg, inf|
190
+ map_single_callback_arg arg, inf }
191
+ end
192
+
193
+ def self.map_single_callback_arg arg, info
194
+ type = info.type
195
+ tag = type.tag
196
+
197
+ case tag
198
+ when :interface
199
+ iface = type.interface
200
+ if iface.type == :object
201
+ object_pointer_to_object arg
202
+ else
203
+ arg
204
+ end
205
+ when :utf8
206
+ ptr_to_utf8 arg
207
+ when :void
208
+ if arg.null?
209
+ nil
210
+ else
211
+ begin
212
+ ObjectSpace._id2ref arg.address
213
+ rescue RangeError
201
214
  arg
202
215
  end
203
- }
204
- prc.call(*mapped)
216
+ end
217
+ else
218
+ arg
205
219
  end
206
220
  end
207
221
 
@@ -210,12 +224,6 @@ module GirFFI
210
224
  raise GError.new(errp)[:message] unless errp.null?
211
225
  end
212
226
 
213
- def self.sink_if_floating gobject
214
- if GirFFI::GObject.object_is_floating(gobject)
215
- GirFFI::GObject.object_ref_sink(gobject)
216
- end
217
- end
218
-
219
227
  def self.check_fixed_array_size size, arr, name
220
228
  unless arr.size == size
221
229
  raise ArgumentError, "#{name} should have size #{size}"
@@ -228,11 +236,21 @@ module GirFFI
228
236
 
229
237
  # FIXME: Quasi-circular dependency on generated module
230
238
  def self.object_pointer_to_object optr
239
+ return nil if optr.null?
231
240
  tp = ::GObject.type_from_instance_pointer optr
232
- gir = GirFFI::IRepository.default
233
241
  info = gir.find_by_gtype tp
242
+
243
+ if info.nil?
244
+ tpname = ::GObject.type_name tp
245
+ raise RuntimeError, "Unable to find info for type '#{tpname}' (#{tp})"
246
+ end
247
+
234
248
  klass = GirFFI::Builder.build_class info.namespace, info.name
235
249
  klass.wrap optr
236
250
  end
251
+
252
+ def self.gir
253
+ gir = GirFFI::IRepository.default
254
+ end
237
255
  end
238
256
  end
@@ -0,0 +1,382 @@
1
+ module GirFFI
2
+ # Abstract parent class of the argument building classes. These classes
3
+ # are used by FunctionDefinitionBuilder to create the code that processes
4
+ # each argument before and after the actual function call.
5
+ class ArgumentBuilder
6
+ KEYWORDS = [
7
+ "alias", "and", "begin", "break", "case", "class", "def", "do",
8
+ "else", "elsif", "end", "ensure", "false", "for", "if", "in",
9
+ "module", "next", "nil", "not", "or", "redo", "rescue", "retry",
10
+ "return", "self", "super", "then", "true", "undef", "unless",
11
+ "until", "when", "while", "yield"
12
+ ]
13
+
14
+ attr_reader :arginfo, :callarg, :pre, :post, :postpost
15
+
16
+ attr_accessor :length_arg, :inarg, :retval
17
+
18
+ def initialize function_builder, arginfo=nil, libmodule=nil
19
+ @arginfo = arginfo
20
+ @inarg = nil
21
+ @callarg = nil
22
+ @retval = nil
23
+ @retname = nil
24
+ @name = nil
25
+ @pre = []
26
+ @post = []
27
+ @postpost = []
28
+ @function_builder = function_builder
29
+ @libmodule = libmodule
30
+ end
31
+
32
+ def self.build function_builder, arginfo, libmodule
33
+ klass = case arginfo.direction
34
+ when :inout
35
+ InOutArgumentBuilder
36
+ when :in
37
+ InArgumentBuilder
38
+ when :out
39
+ OutArgumentBuilder
40
+ else
41
+ raise ArgumentError
42
+ end
43
+ klass.new function_builder, arginfo, libmodule
44
+ end
45
+
46
+ def type
47
+ @arginfo.type
48
+ end
49
+
50
+ private
51
+
52
+ def safe name
53
+ if KEYWORDS.include? name
54
+ "#{name}_"
55
+ else
56
+ name
57
+ end
58
+ end
59
+ end
60
+
61
+ # Implements argument processing for arguments with direction :in
62
+ class InArgumentBuilder < ArgumentBuilder
63
+ def prepare
64
+ @name = safe(@arginfo.name)
65
+ @callarg = @function_builder.new_var
66
+ @inarg = @name
67
+ end
68
+
69
+ def process
70
+ case @arginfo.type.tag
71
+ when :interface
72
+ process_interface_in_arg
73
+ when :void
74
+ process_void_in_arg
75
+ when :array
76
+ process_array_in_arg
77
+ when :utf8
78
+ process_utf8_in_arg
79
+ else
80
+ process_other_in_arg
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+
87
+ def process_interface_in_arg
88
+ arg = @arginfo
89
+ type = arg.type
90
+
91
+ iface = type.interface
92
+ if iface.type == :callback
93
+ @pre << "#{@callarg} = GirFFI::ArgHelper.wrap_in_callback_args_mapper \"#{iface.namespace}\", \"#{iface.name}\", #{@inarg}"
94
+ @pre << "::#{@libmodule}::CALLBACKS << #{@callarg}"
95
+ else
96
+ @pre << "#{@callarg} = #{@inarg}"
97
+ end
98
+ end
99
+
100
+ def process_void_in_arg
101
+ @pre << "#{@callarg} = GirFFI::ArgHelper.object_to_inptr #{@inarg}"
102
+ end
103
+
104
+ def process_utf8_in_arg
105
+ @pre << "#{@callarg} = GirFFI::ArgHelper.utf8_to_inptr #{@name}"
106
+ # TODO:
107
+ #@post << "GirFFI::ArgHelper.cleanup_ptr #{@callarg}"
108
+ end
109
+
110
+ def process_array_in_arg
111
+ arg = @arginfo
112
+ type = arg.type
113
+
114
+ if type.array_fixed_size > 0
115
+ @pre << "GirFFI::ArgHelper.check_fixed_array_size #{type.array_fixed_size}, #{@inarg}, \"#{@inarg}\""
116
+ elsif type.array_length > -1
117
+ idx = type.array_length
118
+ lenvar = @length_arg.inarg
119
+ @length_arg.inarg = nil
120
+ @length_arg.pre.unshift "#{lenvar} = #{@inarg}.nil? ? 0 : #{@inarg}.length"
121
+ end
122
+
123
+ tag = arg.type.param_type(0).tag.to_s.downcase
124
+ @pre << "#{@callarg} = GirFFI::ArgHelper.#{tag}_array_to_inptr #{@inarg}"
125
+ unless arg.ownership_transfer == :everything
126
+ if tag == :utf8
127
+ @post << "GirFFI::ArgHelper.cleanup_ptr_ptr #{@callarg}"
128
+ else
129
+ @post << "GirFFI::ArgHelper.cleanup_ptr #{@callarg}"
130
+ end
131
+ end
132
+ end
133
+
134
+ def process_other_in_arg
135
+ @pre << "#{@callarg} = #{@name}"
136
+ end
137
+ end
138
+
139
+ # Implements argument processing for arguments with direction :out
140
+ class OutArgumentBuilder < ArgumentBuilder
141
+ def prepare
142
+ @name = safe(@arginfo.name)
143
+ @callarg = @function_builder.new_var
144
+ @retname = @retval = @function_builder.new_var
145
+ end
146
+
147
+ def process
148
+ case @arginfo.type.tag
149
+ when :interface
150
+ process_interface_out_arg
151
+ when :array
152
+ process_array_out_arg
153
+ else
154
+ process_other_out_arg
155
+ end
156
+ end
157
+
158
+ private
159
+
160
+ def process_interface_out_arg
161
+ iface = @arginfo.type.interface
162
+ klass = "#{iface.namespace}::#{iface.name}"
163
+
164
+ if @arginfo.caller_allocates?
165
+ @pre << "#{@callarg} = #{klass}.allocate"
166
+ @post << "#{@retval} = #{@callarg}"
167
+ else
168
+ @pre << "#{@callarg} = GirFFI::ArgHelper.pointer_outptr"
169
+ @post << "#{@retval} = #{klass}.wrap GirFFI::ArgHelper.outptr_to_pointer(#{@callarg})"
170
+ end
171
+ end
172
+
173
+ def process_array_out_arg
174
+ @pre << "#{@callarg} = GirFFI::ArgHelper.pointer_outptr"
175
+
176
+ arg = @arginfo
177
+ type = arg.type
178
+ tag = type.param_type(0).tag
179
+ size = type.array_fixed_size
180
+ idx = type.array_length
181
+
182
+ if size <= 0
183
+ if idx > -1
184
+ size = @length_arg.retval
185
+ @length_arg.retval = nil
186
+ else
187
+ raise NotImplementedError
188
+ end
189
+ end
190
+
191
+ @postpost << "#{@retval} = GirFFI::ArgHelper.outptr_to_#{tag}_array #{@callarg}, #{size}"
192
+
193
+ if arg.ownership_transfer == :everything
194
+ if tag == :utf8
195
+ @postpost << "GirFFI::ArgHelper.cleanup_ptr_array_ptr #{@callarg}, #{rv}"
196
+ else
197
+ @postpost << "GirFFI::ArgHelper.cleanup_ptr_ptr #{@callarg}"
198
+ end
199
+ end
200
+ end
201
+
202
+ def process_other_out_arg
203
+ tag = @arginfo.type.tag
204
+ @pre << "#{@callarg} = GirFFI::ArgHelper.#{tag}_outptr"
205
+ @post << "#{@retname} = GirFFI::ArgHelper.outptr_to_#{tag} #{@callarg}"
206
+ if @arginfo.ownership_transfer == :everything
207
+ @post << "GirFFI::ArgHelper.cleanup_ptr #{@callarg}"
208
+ end
209
+ end
210
+
211
+ end
212
+
213
+ # Implements argument processing for arguments with direction :inout
214
+ class InOutArgumentBuilder < ArgumentBuilder
215
+ def prepare
216
+ @name = safe(@arginfo.name)
217
+ @callarg = @function_builder.new_var
218
+ @inarg = @name
219
+ @retname = @retval = @function_builder.new_var
220
+ end
221
+
222
+ def process
223
+ raise NotImplementedError unless @arginfo.ownership_transfer == :everything
224
+
225
+ case @arginfo.type.tag
226
+ when :interface
227
+ process_interface_inout_arg
228
+ when :array
229
+ process_array_inout_arg
230
+ else
231
+ process_other_inout_arg
232
+ end
233
+ end
234
+
235
+ private
236
+
237
+ def process_interface_inout_arg
238
+ raise NotImplementedError
239
+ end
240
+
241
+ def process_array_inout_arg
242
+ arg = @arginfo
243
+ tag = arg.type.param_type(0).tag
244
+ @pre << "#{@callarg} = GirFFI::ArgHelper.#{tag}_array_to_inoutptr #{@inarg}"
245
+ if arg.type.array_length > -1
246
+ idx = arg.type.array_length
247
+ rv = @length_arg.retval
248
+ @length_arg.retval = nil
249
+ lname = @length_arg.inarg
250
+ @length_arg.inarg = nil
251
+ @length_arg.pre.unshift "#{lname} = #{@inarg}.length"
252
+ @post << "#{@retval} = GirFFI::ArgHelper.outptr_to_#{tag}_array #{@callarg}, #{rv}"
253
+ if tag == :utf8
254
+ @post << "GirFFI::ArgHelper.cleanup_ptr_array_ptr #{@callarg}, #{rv}"
255
+ else
256
+ @post << "GirFFI::ArgHelper.cleanup_ptr_ptr #{@callarg}"
257
+ end
258
+ else
259
+ raise NotImplementedError
260
+ end
261
+ end
262
+
263
+ def process_other_inout_arg
264
+ tag = @arginfo.type.tag
265
+ @pre << "#{@callarg} = GirFFI::ArgHelper.#{tag}_to_inoutptr #{@inarg}"
266
+ @post << "#{@retval} = GirFFI::ArgHelper.outptr_to_#{tag} #{@callarg}"
267
+ @post << "GirFFI::ArgHelper.cleanup_ptr #{@callarg}"
268
+ end
269
+ end
270
+
271
+ # Implements argument processing for return values.
272
+ class ReturnValueBuilder < ArgumentBuilder
273
+ attr_reader :cvar
274
+
275
+ def prepare
276
+ return if tag == :void
277
+ @cvar = @function_builder.new_var
278
+ @retval = @function_builder.new_var
279
+ end
280
+
281
+ def process
282
+ return if tag == :void
283
+
284
+ type = @arginfo.return_type
285
+
286
+ case tag
287
+ when :interface
288
+ process_interface_return_value type, @cvar
289
+ when :array
290
+ process_array_return_value type, @cvar
291
+ else
292
+ process_other_return_value
293
+ end
294
+ end
295
+
296
+ def type
297
+ @arginfo.return_type
298
+ end
299
+
300
+ private
301
+
302
+ def process_interface_return_value type, cvar
303
+ interface = type.interface
304
+ namespace = interface.namespace
305
+ name = interface.name
306
+
307
+ case interface.type
308
+ when :interface
309
+ GirFFI::Builder.build_class namespace, name
310
+ @post << "#{@retval} = ::#{namespace}::#{name}.wrap(#{cvar})"
311
+ when :object
312
+ if @arginfo.constructor?
313
+ GirFFI::Builder.build_class namespace, name
314
+ @post << "#{@retval} = ::#{namespace}::#{name}.wrap(#{cvar})"
315
+ if is_subclass_of_initially_unowned interface
316
+ @post << "GirFFI::GObject.object_ref_sink(#{@retval})"
317
+ end
318
+ else
319
+ @post << "#{@retval} = GirFFI::ArgHelper.object_pointer_to_object(#{cvar})"
320
+ end
321
+ when :struct
322
+ GirFFI::Builder.build_class namespace, name
323
+ @post << "#{@retval} = ::#{namespace}::#{name}.wrap(#{cvar})"
324
+ else
325
+ @post << "#{@retval} = #{cvar}"
326
+ end
327
+ end
328
+
329
+ def process_array_return_value type, cvar
330
+ tag = type.param_type(0).tag
331
+ size = type.array_fixed_size
332
+ idx = type.array_length
333
+
334
+ if size > 0
335
+ @post << "#{@retval} = GirFFI::ArgHelper.ptr_to_#{tag}_array #{cvar}, #{size}"
336
+ elsif idx > -1
337
+ lendata = @length_arg #@data[idx]
338
+ rv = lendata.retval
339
+ lendata.retval = nil
340
+ @post << "#{@retval} = GirFFI::ArgHelper.ptr_to_#{tag}_array #{cvar}, #{rv}"
341
+ end
342
+ end
343
+
344
+ def process_other_return_value
345
+ @retval = @cvar
346
+ end
347
+
348
+ def tag
349
+ type.tag
350
+ end
351
+
352
+ def is_subclass_of_initially_unowned interface
353
+ if interface.namespace == "GObject" and interface.name == "InitiallyUnowned"
354
+ true
355
+ elsif interface.parent
356
+ is_subclass_of_initially_unowned interface.parent
357
+ else
358
+ false
359
+ end
360
+ end
361
+ end
362
+
363
+ # Implements argument processing for error handling arguments. These
364
+ # arguments are not part of the introspected signature, but their
365
+ # presence is indicated by the 'throws' attribute of the function.
366
+ class ErrorHandlerBuilder < ArgumentBuilder
367
+ def prepare
368
+ @callarg = @function_builder.new_var
369
+ end
370
+
371
+ def process
372
+ @pre << "#{@callarg} = FFI::MemoryPointer.new(:pointer).write_pointer nil"
373
+ @post << "GirFFI::ArgHelper.check_error(#{@callarg})"
374
+ end
375
+ end
376
+
377
+ # Argument builder that does nothing. Implements Null Object pattern.
378
+ class NullArgumentBuilder < ArgumentBuilder
379
+ def prepare; end
380
+ def process; end
381
+ end
382
+ end
@@ -30,8 +30,8 @@ module GirFFI
30
30
  # All methods below will be made private at the end.
31
31
 
32
32
  def self.ffi_function_argument_types info
33
- types = info.args.map do |a|
34
- tp = iarginfo_to_ffitype a
33
+ types = info.args.map do |arg|
34
+ tp = iarginfo_to_ffitype arg
35
35
  tp == :string ? :pointer : tp
36
36
  end
37
37
  if info.type == :function
@@ -93,8 +93,8 @@ module GirFFI
93
93
  end
94
94
 
95
95
  # Set up method access.
96
- (self.public_methods - Module.public_methods).each do |m|
97
- private_class_method m.to_sym
96
+ (self.public_methods - Module.public_methods).each do |method|
97
+ private_class_method method.to_sym
98
98
  end
99
99
  public_class_method :build_module, :build_class
100
100
  public_class_method :itypeinfo_to_ffitype
@@ -37,15 +37,10 @@ module GirFFI
37
37
  end
38
38
 
39
39
  def find_signal signal_name
40
- info.signals.each do |s|
41
- return s if s.name == signal_name
42
- end
43
- if info.type == :object
44
- info.interfaces.each do |i|
45
- i.signals.each do |s|
46
- return s if s.name == signal_name
47
- end
48
- end
40
+ signal_definers.each do |inf|
41
+ inf.signals.each do |sig|
42
+ return sig if sig.name == signal_name
43
+ end
49
44
  end
50
45
  if info.parent
51
46
  return superclass.gir_ffi_builder.find_signal signal_name
@@ -57,14 +52,14 @@ module GirFFI
57
52
  def build_class
58
53
  unless defined? @klass
59
54
  case info.type
60
- when :object, :struct
61
- instantiate_struct_class
62
- when :union
63
- instantiate_union_class
64
- when :enum, :flags
65
- instantiate_enum_class
66
- else
67
- raise NotImplementedError, "Cannot build classes of type #{info.type}"
55
+ when :object, :struct, :interface
56
+ instantiate_struct_class
57
+ when :union
58
+ instantiate_union_class
59
+ when :enum, :flags
60
+ instantiate_enum_class
61
+ else
62
+ raise NotImplementedError, "Cannot build classes of type #{info.type}"
68
63
  end
69
64
  end
70
65
  @klass
@@ -118,7 +113,7 @@ module GirFFI
118
113
 
119
114
  def instantiate_enum_class
120
115
  @klass = optionally_define_constant namespace_module, @classname do
121
- vals = info.values.map {|v| [v.name.to_sym, v.value]}.flatten
116
+ vals = info.values.map {|vinfo| [vinfo.name.to_sym, vinfo.value]}.flatten
122
117
  lib.enum(@classname.to_sym, vals)
123
118
  end
124
119
  end
@@ -139,7 +134,11 @@ module GirFFI
139
134
  end
140
135
 
141
136
  def layout_specification
142
- fields = info.fields
137
+ fields = if info.type == :interface
138
+ []
139
+ else
140
+ info.fields
141
+ end
143
142
 
144
143
  if fields.empty?
145
144
  if parent
@@ -149,10 +148,10 @@ module GirFFI
149
148
  end
150
149
  end
151
150
 
152
- fields.map do |f|
153
- [ f.name.to_sym,
154
- itypeinfo_to_ffitype_for_struct(f.type),
155
- f.offset ]
151
+ fields.map do |finfo|
152
+ [ finfo.name.to_sym,
153
+ itypeinfo_to_ffitype_for_struct(finfo.type),
154
+ finfo.offset ]
156
155
  end.flatten
157
156
  end
158
157
 
@@ -168,14 +167,14 @@ module GirFFI
168
167
  end
169
168
 
170
169
  def stub_methods
171
- info.methods.each do |m|
172
- @klass.class_eval method_stub(m.method? ? m.name : "self.#{m.name}", m.name)
170
+ info.methods.each do |minfo|
171
+ @klass.class_eval method_stub(minfo.name, minfo.method?)
173
172
  end
174
173
  end
175
174
 
176
- def method_stub name, symbol
175
+ def method_stub symbol, is_instance_method
177
176
  "
178
- def #{name} *args, &block
177
+ def #{is_instance_method ? '' : 'self.'}#{symbol} *args, &block
179
178
  setup_and_call :#{symbol}, *args, &block
180
179
  end
181
180
  "
@@ -193,13 +192,13 @@ module GirFFI
193
192
  end
194
193
 
195
194
  def setup_vfunc_invokers
196
- info.vfuncs.each do |v|
197
- invoker = v.invoker
195
+ info.vfuncs.each do |vfinfo|
196
+ invoker = vfinfo.invoker
198
197
  next if invoker.nil?
199
- next if invoker.name == v.name
198
+ next if invoker.name == vfinfo.name
200
199
 
201
200
  @klass.class_eval "
202
- def #{v.name} *args, &block
201
+ def #{vfinfo.name} *args, &block
203
202
  #{invoker.name}(*args, &block)
204
203
  end
205
204
  "
@@ -228,8 +227,8 @@ module GirFFI
228
227
  end
229
228
 
230
229
  def instance_method_introspection_data method
231
- m = method_introspection_data method
232
- return !m.nil? && m.method? ? m : nil
230
+ data = method_introspection_data method
231
+ return !data.nil? && data.method? ? data : nil
233
232
  end
234
233
 
235
234
  def function_definition go
@@ -257,5 +256,9 @@ module GirFFI
257
256
  Class.new parent
258
257
  }
259
258
  end
259
+
260
+ def signal_definers
261
+ [info] + (info.type == :object ? info.interfaces : [])
262
+ end
260
263
  end
261
264
  end