gir_ffi 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/DESIGN.rdoc +9 -0
- data/History.txt +11 -0
- data/TODO.rdoc +6 -9
- data/examples/01_empty_window.rb +1 -1
- data/examples/02_hello_world.rb +4 -4
- data/examples/03_upgraded_hello_world.rb +7 -8
- data/lib/gir_ffi.rb +0 -4
- data/lib/gir_ffi/arg_helper.rb +27 -2
- data/lib/gir_ffi/builder.rb +13 -86
- data/lib/gir_ffi/builder_helper.rb +2 -15
- data/lib/gir_ffi/class_base.rb +51 -0
- data/lib/gir_ffi/class_builder.rb +178 -52
- data/lib/gir_ffi/function_definition_builder.rb +46 -9
- data/lib/gir_ffi/g_object.rb +37 -0
- data/lib/gir_ffi/i_arg_info.rb +27 -9
- data/lib/gir_ffi/i_base_info.rb +12 -4
- data/lib/gir_ffi/i_callable_info.rb +15 -5
- data/lib/gir_ffi/i_enum_info.rb +9 -3
- data/lib/gir_ffi/i_field_info.rb +12 -4
- data/lib/gir_ffi/i_function_info.rb +24 -8
- data/lib/gir_ffi/i_object_info.rb +63 -21
- data/lib/gir_ffi/i_registered_type_info.rb +11 -0
- data/lib/gir_ffi/i_repository.rb +2 -2
- data/lib/gir_ffi/i_signal_info.rb +1 -1
- data/lib/gir_ffi/i_struct_info.rb +24 -8
- data/lib/gir_ffi/i_type_info.rb +24 -8
- data/lib/gir_ffi/i_union_info.rb +15 -0
- data/lib/gir_ffi/i_value_info.rb +3 -1
- data/lib/gir_ffi/i_vfunc_info.rb +12 -1
- data/lib/gir_ffi/lib.rb +23 -1
- data/lib/gir_ffi/lib_c.rb +1 -1
- data/lib/gir_ffi/module_base.rb +19 -0
- data/lib/gir_ffi/module_builder.rb +67 -20
- data/lib/gir_ffi/overrides/gobject.rb +174 -0
- data/lib/gir_ffi/overrides/gtk.rb +26 -9
- data/test/builder_test.rb +57 -37
- data/test/{base_test.rb → class_base_test.rb} +3 -3
- data/test/class_builder_test.rb +48 -6
- data/test/everything_test.rb +285 -36
- data/test/function_definition_builder_test.rb +11 -9
- data/test/g_object_test.rb +22 -0
- data/test/gobject_overrides_test.rb +216 -0
- data/test/i_object_info_test.rb +21 -0
- data/test/module_builder_test.rb +54 -0
- data/test/test_helper.rb +6 -4
- metadata +18 -14
- data/lib/gir_ffi/base.rb +0 -25
- data/lib/gir_ffi/constructor_definition_builder.rb +0 -20
- data/lib/gir_ffi/g_type.rb +0 -14
- data/lib/gir_ffi/method_missing_definition_builder.rb +0 -59
- data/test/constructor_definition_builder_test.rb +0 -19
- data/test/g_type_test.rb +0 -22
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'gir_ffi/builder_helper'
|
1
2
|
module GirFFI
|
2
3
|
# Builds a class based on information found in the introspection
|
3
4
|
# repository.
|
4
5
|
class ClassBuilder
|
6
|
+
include BuilderHelper
|
5
7
|
def initialize namespace, classname
|
6
8
|
@namespace = namespace
|
7
9
|
@classname = classname
|
@@ -11,61 +13,120 @@ module GirFFI
|
|
11
13
|
build_class
|
12
14
|
end
|
13
15
|
|
16
|
+
def setup_method method
|
17
|
+
definition = prepare_method method.to_s
|
18
|
+
|
19
|
+
return false if definition.nil?
|
20
|
+
|
21
|
+
klass = build_class
|
22
|
+
meta = (class << klass; self; end)
|
23
|
+
meta.class_eval definition
|
24
|
+
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def setup_instance_method method
|
29
|
+
definition = prepare_method method.to_s
|
30
|
+
|
31
|
+
if definition.nil?
|
32
|
+
if parent
|
33
|
+
return superclass.gir_ffi_builder.setup_instance_method method
|
34
|
+
else
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
klass = build_class
|
40
|
+
klass.class_eval "undef #{method}"
|
41
|
+
klass.class_eval definition
|
42
|
+
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def find_signal signal_name
|
47
|
+
info.signals.each do |s|
|
48
|
+
return s if s.name == signal_name
|
49
|
+
end
|
50
|
+
if info.parent
|
51
|
+
return superclass.gir_ffi_builder.find_signal signal_name
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
14
55
|
private
|
15
56
|
|
16
57
|
def build_class
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
@
|
27
|
-
|
58
|
+
unless defined? @klass
|
59
|
+
case info.type
|
60
|
+
when :object, :struct
|
61
|
+
instantiate_class
|
62
|
+
setup_class unless already_set_up
|
63
|
+
when :union
|
64
|
+
instantiate_union_class
|
65
|
+
setup_class unless already_set_up
|
66
|
+
when :enum, :flags
|
67
|
+
@klass = optionally_define_constant namespace_module, @classname do
|
68
|
+
vals = info.values.map {|v| [v.name.to_sym, v.value]}.flatten
|
69
|
+
lib.enum(@classname.to_sym, vals)
|
70
|
+
end
|
71
|
+
else
|
72
|
+
raise NotImplementedError, "Cannot build classes of type #{info.type}"
|
73
|
+
end
|
28
74
|
end
|
29
75
|
@klass
|
30
76
|
end
|
31
77
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
78
|
+
def info
|
79
|
+
unless defined? @info
|
80
|
+
@info = gir.find_by_name @namespace, @classname
|
81
|
+
raise "Class #{@classname} not found in namespace #{@namespace}" if @info.nil?
|
82
|
+
end
|
83
|
+
@info
|
84
|
+
end
|
35
85
|
|
36
|
-
|
37
|
-
|
86
|
+
def parent
|
87
|
+
unless defined? @parent
|
88
|
+
@parent = info.type == :object ? info.parent : nil
|
89
|
+
end
|
90
|
+
@parent
|
38
91
|
end
|
39
92
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
93
|
+
def superclass
|
94
|
+
unless defined? @superclass
|
95
|
+
if parent
|
96
|
+
@superclass = Builder.build_class parent.namespace, parent.name
|
97
|
+
else
|
98
|
+
@superclass = GirFFI::ClassBase
|
99
|
+
end
|
46
100
|
end
|
101
|
+
@superclass
|
102
|
+
end
|
103
|
+
|
104
|
+
def namespace_module
|
105
|
+
@namespace_module ||= Builder.build_module @namespace
|
47
106
|
end
|
48
107
|
|
49
|
-
def
|
50
|
-
@
|
51
|
-
@lib = @module.const_get :Lib
|
108
|
+
def lib
|
109
|
+
@lib ||= namespace_module.const_get :Lib
|
52
110
|
end
|
53
111
|
|
54
112
|
def instantiate_class
|
55
|
-
|
56
|
-
@
|
57
|
-
|
113
|
+
@klass = get_or_define_class namespace_module, @classname, superclass
|
114
|
+
@structklass = get_or_define_class @klass, :Struct, FFI::Struct
|
115
|
+
end
|
116
|
+
|
117
|
+
def instantiate_union_class
|
118
|
+
@klass = get_or_define_class namespace_module, @classname, superclass
|
119
|
+
@structklass = get_or_define_class @klass, :Struct, FFI::Union
|
58
120
|
end
|
59
121
|
|
60
122
|
def setup_class
|
61
|
-
setup_method_missing
|
62
123
|
setup_layout
|
63
|
-
|
64
|
-
|
124
|
+
setup_constants
|
125
|
+
setup_instance_methods
|
126
|
+
setup_gtype_getter
|
65
127
|
|
66
|
-
|
67
|
-
|
68
|
-
@klass.class_eval class_method_missing_definition
|
128
|
+
setup_vfunc_invokers if info.type == :object
|
129
|
+
provide_struct_constructor if info.type == :struct
|
69
130
|
end
|
70
131
|
|
71
132
|
def setup_layout
|
@@ -74,30 +135,34 @@ module GirFFI
|
|
74
135
|
end
|
75
136
|
|
76
137
|
def layout_specification
|
77
|
-
|
78
|
-
|
79
|
-
|
138
|
+
fields = info.fields
|
139
|
+
|
140
|
+
if fields.empty?
|
141
|
+
if parent
|
142
|
+
return [:parent, superclass.const_get(:Struct), 0]
|
80
143
|
end
|
81
144
|
end
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
88
|
-
spec
|
145
|
+
|
146
|
+
fields.map do |f|
|
147
|
+
[ f.name.to_sym,
|
148
|
+
itypeinfo_to_ffitype_for_struct(f.type),
|
149
|
+
f.offset ]
|
150
|
+
end.flatten
|
89
151
|
end
|
90
152
|
|
91
153
|
def itypeinfo_to_ffitype_for_struct typeinfo
|
92
154
|
ffitype = Builder.itypeinfo_to_ffitype typeinfo
|
93
|
-
if ffitype.kind_of?(Class) and
|
155
|
+
if ffitype.kind_of?(Class) and const_defined_for ffitype, :Struct
|
94
156
|
ffitype = ffitype.const_get :Struct
|
95
157
|
end
|
158
|
+
if ffitype == :bool
|
159
|
+
ffitype = :int
|
160
|
+
end
|
96
161
|
ffitype
|
97
162
|
end
|
98
163
|
|
99
|
-
def
|
100
|
-
|
164
|
+
def setup_instance_methods
|
165
|
+
info.methods.each do |m|
|
101
166
|
@klass.class_eval "
|
102
167
|
def #{m.name} *args, &block
|
103
168
|
method_missing :#{m.name}, *args, &block
|
@@ -106,16 +171,77 @@ module GirFFI
|
|
106
171
|
end
|
107
172
|
end
|
108
173
|
|
109
|
-
def
|
110
|
-
|
174
|
+
def setup_gtype_getter
|
175
|
+
getter = info.type_init
|
176
|
+
return if getter.nil? or getter == "intern"
|
177
|
+
lib.attach_function getter.to_sym, [], :int
|
178
|
+
@klass.class_eval "
|
179
|
+
def self.get_gtype
|
180
|
+
::#{lib}.#{getter}
|
181
|
+
end
|
182
|
+
"
|
183
|
+
end
|
184
|
+
|
185
|
+
def setup_vfunc_invokers
|
186
|
+
info.vfuncs.each do |v|
|
187
|
+
invoker = v.invoker
|
188
|
+
next if invoker.nil?
|
189
|
+
next if invoker.name == v.name
|
190
|
+
|
191
|
+
@klass.class_eval "
|
192
|
+
def #{v.name} *args, &block
|
193
|
+
#{invoker.name}(*args, &block)
|
194
|
+
end
|
195
|
+
"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def provide_struct_constructor
|
200
|
+
return if info.find_method 'new'
|
201
|
+
|
202
|
+
(class << @klass; self; end).class_eval {
|
203
|
+
alias_method :new, :_real_new
|
204
|
+
}
|
111
205
|
end
|
112
206
|
|
113
|
-
def
|
114
|
-
|
207
|
+
def setup_constants
|
208
|
+
@klass.const_set :GIR_INFO, info
|
209
|
+
@klass.const_set :GIR_FFI_BUILDER, self
|
115
210
|
end
|
116
211
|
|
117
212
|
def already_set_up
|
118
|
-
@klass
|
213
|
+
const_defined_for @klass, :GIR_FFI_BUILDER
|
214
|
+
end
|
215
|
+
|
216
|
+
def method_introspection_data method
|
217
|
+
info.find_method method
|
218
|
+
end
|
219
|
+
|
220
|
+
def function_definition go
|
221
|
+
FunctionDefinitionBuilder.new(go, lib).generate
|
222
|
+
end
|
223
|
+
|
224
|
+
def prepare_method method
|
225
|
+
go = method_introspection_data method
|
226
|
+
|
227
|
+
return nil if go.nil?
|
228
|
+
|
229
|
+
Builder.attach_ffi_function lib, go
|
230
|
+
function_definition go
|
231
|
+
end
|
232
|
+
|
233
|
+
def gir
|
234
|
+
unless defined? @gir
|
235
|
+
@gir = IRepository.default
|
236
|
+
@gir.require @namespace, nil
|
237
|
+
end
|
238
|
+
@gir
|
239
|
+
end
|
240
|
+
|
241
|
+
def get_or_define_class namespace, name, parent
|
242
|
+
optionally_define_constant(namespace, name) {
|
243
|
+
Class.new parent
|
244
|
+
}
|
119
245
|
end
|
120
246
|
end
|
121
247
|
end
|
@@ -44,8 +44,10 @@ module GirFFI
|
|
44
44
|
process_inout_arg arg
|
45
45
|
when :in
|
46
46
|
process_in_arg arg
|
47
|
+
when :out
|
48
|
+
process_out_arg arg
|
47
49
|
else
|
48
|
-
raise
|
50
|
+
raise ArgumentError
|
49
51
|
end
|
50
52
|
end
|
51
53
|
|
@@ -76,6 +78,34 @@ module GirFFI
|
|
76
78
|
@retvals << postvar
|
77
79
|
end
|
78
80
|
|
81
|
+
def process_out_arg arg
|
82
|
+
prevar = new_var
|
83
|
+
postvar = new_var
|
84
|
+
|
85
|
+
case arg.type.tag
|
86
|
+
when :int, :int32
|
87
|
+
@pre << "#{prevar} = GirFFI::ArgHelper.int_to_inoutptr 0"
|
88
|
+
@post << "#{postvar} = GirFFI::ArgHelper.outptr_to_int #{prevar}"
|
89
|
+
when :double
|
90
|
+
@pre << "#{prevar} = GirFFI::ArgHelper.double_to_inoutptr 0"
|
91
|
+
@post << "#{postvar} = GirFFI::ArgHelper.outptr_to_double #{prevar}"
|
92
|
+
when :interface
|
93
|
+
iface = arg.type.interface
|
94
|
+
if iface.type == :struct
|
95
|
+
@pre << "#{prevar} = #{iface.namespace}::#{iface.name}.new"
|
96
|
+
@post << "#{postvar} = #{prevar}"
|
97
|
+
else
|
98
|
+
raise NotImplementedError,
|
99
|
+
"Don't know what to do with interface type #{iface.type}"
|
100
|
+
end
|
101
|
+
else
|
102
|
+
raise NotImplementedError,
|
103
|
+
"Don't know what to do with argument type #{arg.type.tag}"
|
104
|
+
end
|
105
|
+
@callargs << prevar
|
106
|
+
@retvals << postvar
|
107
|
+
end
|
108
|
+
|
79
109
|
def process_in_arg arg
|
80
110
|
name = safe arg.name
|
81
111
|
type = arg.type
|
@@ -87,7 +117,7 @@ module GirFFI
|
|
87
117
|
# TODO: Use arg.scope to decide if this is needed.
|
88
118
|
procvar = new_var
|
89
119
|
@pre << "#{procvar} = GirFFI::ArgHelper.mapped_callback_args #{name}"
|
90
|
-
@pre << "
|
120
|
+
@pre << "::#{@libmodule}::CALLBACKS << #{procvar}"
|
91
121
|
@callargs << procvar
|
92
122
|
elsif tag == :void
|
93
123
|
raise NotImplementedError unless arg.type.pointer?
|
@@ -103,15 +133,22 @@ module GirFFI
|
|
103
133
|
type = @info.return_type
|
104
134
|
tag = type.tag
|
105
135
|
return if tag == :void
|
106
|
-
|
107
|
-
@capture = "#{
|
136
|
+
cvar = new_var
|
137
|
+
@capture = "#{cvar} = "
|
108
138
|
|
109
139
|
if tag == :interface
|
110
140
|
interface = type.interface
|
111
|
-
|
112
|
-
|
113
|
-
|
141
|
+
namespace = interface.namespace
|
142
|
+
name = interface.name
|
143
|
+
GirFFI::Builder.build_class namespace, name
|
144
|
+
retval = new_var
|
145
|
+
@post << "#{retval} = ::#{namespace}::#{name}._real_new(#{cvar})"
|
146
|
+
if interface.type == :object
|
147
|
+
@post << "GirFFI::ArgHelper.sink_if_floating(#{retval})"
|
148
|
+
end
|
114
149
|
@retvals << retval
|
150
|
+
else
|
151
|
+
@retvals << cvar
|
115
152
|
end
|
116
153
|
end
|
117
154
|
|
@@ -119,7 +156,7 @@ module GirFFI
|
|
119
156
|
if @info.throws?
|
120
157
|
errvar = new_var
|
121
158
|
@pre << "#{errvar} = FFI::MemoryPointer.new(:pointer).write_pointer nil"
|
122
|
-
@post
|
159
|
+
@post.unshift "GirFFI::ArgHelper.check_error(#{errvar})"
|
123
160
|
@callargs << errvar
|
124
161
|
end
|
125
162
|
|
@@ -134,7 +171,7 @@ module GirFFI
|
|
134
171
|
return <<-CODE
|
135
172
|
def #{@info.name} #{@inargs.join(', ')}
|
136
173
|
#{@pre.join("\n")}
|
137
|
-
#{@capture}
|
174
|
+
#{@capture}::#{@libmodule}.#{@info.symbol} #{@callargs.join(', ')}
|
138
175
|
#{@post.join("\n")}
|
139
176
|
end
|
140
177
|
CODE
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module GirFFI
|
4
|
+
module GObject
|
5
|
+
def self.type_init
|
6
|
+
Lib::g_type_init
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.object_ref o
|
10
|
+
Lib::g_object_ref o.to_ptr
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.object_ref_sink o
|
14
|
+
Lib::g_object_ref_sink o.to_ptr
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.object_unref o
|
18
|
+
Lib::g_object_unref o.to_ptr
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.object_is_floating o
|
22
|
+
Lib::g_object_is_floating o.to_ptr
|
23
|
+
end
|
24
|
+
|
25
|
+
module Lib
|
26
|
+
extend FFI::Library
|
27
|
+
ffi_lib "gobject-2.0"
|
28
|
+
attach_function :g_type_init, [], :void
|
29
|
+
attach_function :g_object_ref, [:pointer], :void
|
30
|
+
attach_function :g_object_ref_sink, [:pointer], :void
|
31
|
+
attach_function :g_object_unref, [:pointer], :void
|
32
|
+
attach_function :g_object_is_floating, [:pointer], :bool
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
data/lib/gir_ffi/i_arg_info.rb
CHANGED
@@ -3,14 +3,32 @@ module GirFFI
|
|
3
3
|
# Wraps a GIArgInfo struct.
|
4
4
|
# Represents an argument.
|
5
5
|
class IArgInfo < IBaseInfo
|
6
|
-
def direction
|
7
|
-
|
8
|
-
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
def
|
13
|
-
|
14
|
-
|
6
|
+
def direction
|
7
|
+
Lib.g_arg_info_get_direction @gobj
|
8
|
+
end
|
9
|
+
def return_value?
|
10
|
+
Lib.g_arg_info_is_return_value @gobj
|
11
|
+
end
|
12
|
+
def optional?
|
13
|
+
Lib.g_arg_info_is_optional @gobj
|
14
|
+
end
|
15
|
+
def may_be_null?
|
16
|
+
Lib.g_arg_info_may_be_null @gobj
|
17
|
+
end
|
18
|
+
def ownership_transfer
|
19
|
+
Lib.g_arg_info_get_ownership_transfer @gobj
|
20
|
+
end
|
21
|
+
def scope
|
22
|
+
Lib.g_arg_info_get_scope @gobj
|
23
|
+
end
|
24
|
+
def closure
|
25
|
+
Lib.g_arg_info_get_closure @gobj
|
26
|
+
end
|
27
|
+
def destroy
|
28
|
+
Lib.g_arg_info_get_destroy @gobj
|
29
|
+
end
|
30
|
+
def type
|
31
|
+
ITypeInfo.wrap(Lib.g_arg_info_get_type @gobj)
|
32
|
+
end
|
15
33
|
end
|
16
34
|
end
|