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.
Files changed (52) hide show
  1. data/DESIGN.rdoc +9 -0
  2. data/History.txt +11 -0
  3. data/TODO.rdoc +6 -9
  4. data/examples/01_empty_window.rb +1 -1
  5. data/examples/02_hello_world.rb +4 -4
  6. data/examples/03_upgraded_hello_world.rb +7 -8
  7. data/lib/gir_ffi.rb +0 -4
  8. data/lib/gir_ffi/arg_helper.rb +27 -2
  9. data/lib/gir_ffi/builder.rb +13 -86
  10. data/lib/gir_ffi/builder_helper.rb +2 -15
  11. data/lib/gir_ffi/class_base.rb +51 -0
  12. data/lib/gir_ffi/class_builder.rb +178 -52
  13. data/lib/gir_ffi/function_definition_builder.rb +46 -9
  14. data/lib/gir_ffi/g_object.rb +37 -0
  15. data/lib/gir_ffi/i_arg_info.rb +27 -9
  16. data/lib/gir_ffi/i_base_info.rb +12 -4
  17. data/lib/gir_ffi/i_callable_info.rb +15 -5
  18. data/lib/gir_ffi/i_enum_info.rb +9 -3
  19. data/lib/gir_ffi/i_field_info.rb +12 -4
  20. data/lib/gir_ffi/i_function_info.rb +24 -8
  21. data/lib/gir_ffi/i_object_info.rb +63 -21
  22. data/lib/gir_ffi/i_registered_type_info.rb +11 -0
  23. data/lib/gir_ffi/i_repository.rb +2 -2
  24. data/lib/gir_ffi/i_signal_info.rb +1 -1
  25. data/lib/gir_ffi/i_struct_info.rb +24 -8
  26. data/lib/gir_ffi/i_type_info.rb +24 -8
  27. data/lib/gir_ffi/i_union_info.rb +15 -0
  28. data/lib/gir_ffi/i_value_info.rb +3 -1
  29. data/lib/gir_ffi/i_vfunc_info.rb +12 -1
  30. data/lib/gir_ffi/lib.rb +23 -1
  31. data/lib/gir_ffi/lib_c.rb +1 -1
  32. data/lib/gir_ffi/module_base.rb +19 -0
  33. data/lib/gir_ffi/module_builder.rb +67 -20
  34. data/lib/gir_ffi/overrides/gobject.rb +174 -0
  35. data/lib/gir_ffi/overrides/gtk.rb +26 -9
  36. data/test/builder_test.rb +57 -37
  37. data/test/{base_test.rb → class_base_test.rb} +3 -3
  38. data/test/class_builder_test.rb +48 -6
  39. data/test/everything_test.rb +285 -36
  40. data/test/function_definition_builder_test.rb +11 -9
  41. data/test/g_object_test.rb +22 -0
  42. data/test/gobject_overrides_test.rb +216 -0
  43. data/test/i_object_info_test.rb +21 -0
  44. data/test/module_builder_test.rb +54 -0
  45. data/test/test_helper.rb +6 -4
  46. metadata +18 -14
  47. data/lib/gir_ffi/base.rb +0 -25
  48. data/lib/gir_ffi/constructor_definition_builder.rb +0 -20
  49. data/lib/gir_ffi/g_type.rb +0 -14
  50. data/lib/gir_ffi/method_missing_definition_builder.rb +0 -59
  51. data/test/constructor_definition_builder_test.rb +0 -19
  52. data/test/g_type_test.rb +0 -22
data/DESIGN.rdoc CHANGED
@@ -45,6 +45,15 @@ GLib::Instantiable; In standard GObject they are functions.
45
45
  Possibly, compatibility enhancing code can be added for these specific
46
46
  exceptions.
47
47
 
48
+ == Reference Counting
49
+
50
+ Because we can always make sure GObjects are unref'd when the Ruby object
51
+ is GC'd, the mechanism of floating references actually gets in the way a
52
+ bit. Therefore, when floating GObjects are constructed, GirFFI will sink
53
+ them. All GObjects can then safely be unref'd using a Ruby finalizer.
54
+ GObjects obtained through other mechanisms than with a constructor will be
55
+ ref'd once when wrapping them in a ruby object.
56
+
48
57
  == Bootstrapping Class Design
49
58
 
50
59
  The interface to the GObject Introspection Repository itself is also
data/History.txt CHANGED
@@ -1,3 +1,14 @@
1
+ == 0.0.4 / 2010-12-14
2
+
3
+ * Lots of changes to the internals.
4
+ * Handle out-only arguments.
5
+ * Make use of callbacks from other namespaces work.
6
+ * Handle virtual methods where the invoker method has a different name.
7
+ * Implement usable signal_connect and signal_emit.
8
+ * Sink floating references when creating a GObject.
9
+ * Implement Union type.
10
+ * Many small bug fixes.
11
+
1
12
  == 0.0.3 / 2010-11-19
2
13
 
3
14
  * Update to restore Ruby 1.9 support.
data/TODO.rdoc CHANGED
@@ -20,20 +20,17 @@ able to pass any Ruby object. On the other hand, these cases cannot be
20
20
  distinguished, based on the GIR data, from methods that take a pointer to
21
21
  any GObject.
22
22
 
23
- I'm currently leaning towards passing the object id as the value of the
24
- 'gpointer'. Special overrided will have to be used for the cases where the
25
- 'gpointer' actually needs to be a GObject. I consider it an omission in
26
- GIRepository that these two cases are not distinguished.
23
+ I'm currently passing the object id as the value of the 'gpointer'. Special
24
+ overrided will have to be used for the cases where the 'gpointer' actually
25
+ needs to be a GObject. I consider it an omission in GIRepository that these
26
+ two cases are not distinguished.
27
27
 
28
28
  == Compatibility with all implementations.
29
29
 
30
30
  Currently, there are the following incompatibilities:
31
31
 
32
- * The MRI implementation does not allow invoking layout more than once. In
33
- particular, this means you cannot subclass a struct and change (augment)
34
- the layout. This *not* a problem in JRuby.
35
-
36
- * JRuby disables ObjectSpace by default, so using _id2ref is not ideal.
32
+ * JRuby disables ObjectSpace by default, so using _id2ref for handling the
33
+ passing of generic pointers is not ideal.
37
34
 
38
35
  == See Also
39
36
 
@@ -11,5 +11,5 @@ GirFFI.setup :Gtk
11
11
  Gtk.init
12
12
  win = Gtk::Window.new :toplevel
13
13
  win.show
14
- GObject.signal_connect_data win, "destroy", Proc.new { Gtk.main_quit }, nil, nil, 0
14
+ GObject.signal_connect(win, "destroy") { Gtk.main_quit }
15
15
  Gtk.main
@@ -11,16 +11,16 @@ GirFFI.setup :Gtk
11
11
  Gtk.init
12
12
 
13
13
  win = Gtk::Window.new(:toplevel)
14
- GObject.signal_connect_data win, "delete-event", FFI::Function.new(:bool, [:pointer, :pointer]) {
14
+ GObject.signal_connect win, "delete-event" do
15
15
  puts "delete event occured"
16
16
  true
17
- }, nil, nil, 0
17
+ end
18
18
 
19
- GObject.signal_connect_data win, "destroy", Proc.new { Gtk.main_quit }, nil, nil, 0
19
+ GObject.signal_connect(win, "destroy") { Gtk.main_quit }
20
20
  win.set_border_width 10
21
21
 
22
22
  but = Gtk::Button.new_with_label("Hello World")
23
- GObject.signal_connect_data but, "clicked", Proc.new { win.destroy }, nil, nil, :swapped
23
+ GObject.signal_connect(but, "clicked") { win.destroy }
24
24
 
25
25
  win.add but
26
26
 
@@ -8,20 +8,19 @@ require 'gir_ffi'
8
8
  GirFFI.setup :GObject
9
9
  GirFFI.setup :Gtk
10
10
 
11
- callback = FFI::Function.new :void, [:pointer, :pointer],
12
- &GirFFI::ArgHelper.mapped_callback_args { |widget, data|
13
- puts "Hello again - #{data} was pressed"
14
- }
11
+ callback = lambda { |widget, data|
12
+ puts "Hello again - #{data} was pressed"
13
+ }
15
14
 
16
15
  Gtk.init
17
16
 
18
17
  win = Gtk::Window.new(:toplevel)
19
18
  win.set_title "Hello Buttons!"
20
19
 
21
- GObject.signal_connect_data win, "delete-event", FFI::Function.new(:bool, [:pointer, :pointer]) {
20
+ GObject.signal_connect win, "delete-event" do
22
21
  Gtk.main_quit
23
22
  false
24
- }, nil, nil, 0
23
+ end
25
24
 
26
25
  win.set_border_width 10
27
26
 
@@ -29,12 +28,12 @@ box = Gtk::HBox.new(false, 0)
29
28
  win.add box
30
29
 
31
30
  button = Gtk::Button.new_with_label("Button 1")
32
- GObject.signal_connect_data button, "clicked", callback, "button 1", nil, 0
31
+ GObject.signal_connect button, "clicked", "button 1", &callback
33
32
  box.pack_start button, true, true, 0
34
33
  button.show
35
34
 
36
35
  button = Gtk::Button.new_with_label("Button 2")
37
- GObject.signal_connect_data button, "clicked", callback, "button 2", nil, 0
36
+ GObject.signal_connect button, "clicked", "button 2", &callback
38
37
  box.pack_start button, true, true, 0
39
38
  button.show
40
39
 
data/lib/gir_ffi.rb CHANGED
@@ -38,10 +38,6 @@ module GirFFI
38
38
  def self.setup module_name
39
39
  module_name = module_name.to_s
40
40
  GirFFI::Builder.build_module module_name
41
- begin
42
- require "gir_ffi/overrides/#{module_name.downcase}"
43
- rescue LoadError
44
- end
45
41
  end
46
42
  end
47
43
  # EOF
@@ -22,14 +22,21 @@ module GirFFI
22
22
  AllocationHelper.safe_malloc(len + 1).write_string(str).put_char(len, 0)
23
23
  }
24
24
 
25
- block = AllocationHelper.safe_malloc FFI.type_size(:pointer) * ptrs.length
25
+ ptr_size = FFI.type_size(:pointer)
26
+ block = AllocationHelper.safe_malloc ptr_size * ptrs.length
26
27
  block.write_array_of_pointer ptrs
27
28
 
28
- argv = AllocationHelper.safe_malloc FFI.type_size(:pointer)
29
+ argv = AllocationHelper.safe_malloc ptr_size
29
30
  argv.write_pointer block
30
31
  argv
31
32
  end
32
33
 
34
+ def self.double_to_inoutptr val
35
+ ptr = AllocationHelper.safe_malloc FFI.type_size(:double)
36
+ ptr.put_double 0, val
37
+ return ptr
38
+ end
39
+
33
40
  # Converts an outptr to an int, then frees the outptr.
34
41
  def self.outptr_to_int ptr
35
42
  value = ptr.read_int
@@ -58,6 +65,13 @@ module GirFFI
58
65
  end
59
66
  end
60
67
 
68
+ # Converts an outptr to a double, then frees the outptr.
69
+ def self.outptr_to_double ptr
70
+ value = ptr.get_double 0
71
+ LibC.free ptr
72
+ value
73
+ end
74
+
61
75
  def self.mapped_callback_args prc=nil, &block
62
76
  return prc if FFI::Function === prc
63
77
  if prc.nil?
@@ -79,5 +93,16 @@ module GirFFI
79
93
  prc.call(*mapped)
80
94
  end
81
95
  end
96
+
97
+ def self.check_error errpp
98
+ errp = errpp.read_pointer
99
+ raise GError.new(errp)[:message] unless errp.null?
100
+ end
101
+
102
+ def self.sink_if_floating gobject
103
+ if GirFFI::GObject.object_is_floating(gobject)
104
+ GirFFI::GObject.object_ref_sink(gobject)
105
+ end
106
+ end
82
107
  end
83
108
  end
@@ -1,8 +1,6 @@
1
1
  require 'gir_ffi/arg_helper'
2
2
  require 'gir_ffi/function_definition_builder'
3
- require 'gir_ffi/constructor_definition_builder'
4
- require 'gir_ffi/method_missing_definition_builder'
5
- require 'gir_ffi/base'
3
+ require 'gir_ffi/class_base'
6
4
  require 'gir_ffi/class_builder'
7
5
  require 'gir_ffi/module_builder'
8
6
  require 'gir_ffi/builder_helper'
@@ -12,6 +10,7 @@ module GirFFI
12
10
  # introspection repository. Call its build_module and build_class methods
13
11
  # to create the modules and classes used in your program.
14
12
  module Builder
13
+ extend BuilderHelper
15
14
  def self.build_class namespace, classname
16
15
  ClassBuilder.new(namespace, classname).generate
17
16
  end
@@ -20,81 +19,6 @@ module GirFFI
20
19
  ModuleBuilder.new(namespace).generate
21
20
  end
22
21
 
23
- def self.setup_method namespace, classname, method
24
- go = method_introspection_data namespace, classname, method.to_s
25
-
26
- return false if go.nil?
27
- return false if go.type != :function
28
-
29
- klass = build_class namespace, classname
30
- modul = build_module namespace
31
- lib = modul.const_get(:Lib)
32
-
33
- attach_ffi_function lib, go
34
-
35
- meta = (class << klass; self; end)
36
- meta.class_eval function_definition(go, lib)
37
-
38
- true
39
- end
40
-
41
- def self.setup_function namespace, method
42
- go = function_introspection_data namespace, method.to_s
43
-
44
- return false if go.nil?
45
- return false if go.type != :function
46
-
47
- modul = build_module namespace
48
- lib = modul.const_get(:Lib)
49
-
50
- attach_ffi_function lib, go
51
-
52
- meta = (class << modul; self; end)
53
- meta.class_eval function_definition(go, lib)
54
-
55
- true
56
- end
57
-
58
- def self.setup_instance_method namespace, classname, method
59
- go = method_introspection_data namespace, classname, method.to_s
60
-
61
- return false if go.nil?
62
- return false if go.type != :function
63
-
64
- klass = build_class namespace, classname
65
- modul = build_module namespace
66
- lib = modul.const_get(:Lib)
67
-
68
- attach_ffi_function lib, go
69
-
70
- klass.class_eval "undef #{method}"
71
- klass.class_eval function_definition(go, lib)
72
-
73
- true
74
- end
75
-
76
- # All methods below will be made private at the end.
77
-
78
- def self.function_definition info, libmodule
79
- if info.constructor?
80
- fdbuilder = ConstructorDefinitionBuilder.new info, libmodule
81
- else
82
- fdbuilder = FunctionDefinitionBuilder.new info, libmodule
83
- end
84
- fdbuilder.generate
85
- end
86
-
87
- def self.function_introspection_data namespace, function
88
- gir = IRepository.default
89
- return gir.find_by_name namespace, function.to_s
90
- end
91
-
92
- def self.method_introspection_data namespace, object, method
93
- gir = IRepository.default
94
- objectinfo = gir.find_by_name namespace, object.to_s
95
- return objectinfo.find_method method
96
- end
97
-
98
22
  def self.attach_ffi_function lib, info
99
23
  sym = info.symbol
100
24
  argtypes = ffi_function_argument_types info
@@ -103,6 +27,8 @@ module GirFFI
103
27
  lib.attach_function sym, argtypes, rt
104
28
  end
105
29
 
30
+ # All methods below will be made private at the end.
31
+
106
32
  def self.ffi_function_argument_types info
107
33
  types = info.args.map do |a|
108
34
  iarginfo_to_ffitype a
@@ -119,11 +45,14 @@ module GirFFI
119
45
  end
120
46
 
121
47
  def self.itypeinfo_to_ffitype info
48
+ tag = info.tag
49
+
122
50
  if info.pointer?
123
- return :string if info.tag == :utf8
51
+ return :string if tag == :utf8
124
52
  return :pointer
125
53
  end
126
- case info.tag
54
+
55
+ case tag
127
56
  when :interface
128
57
  interface = info.interface
129
58
  case interface.type
@@ -139,12 +68,13 @@ module GirFFI
139
68
  when :GType
140
69
  return :int32
141
70
  else
142
- return info.tag
71
+ return tag
143
72
  end
144
73
  end
145
74
 
146
75
  def self.iarginfo_to_ffitype info
147
76
  return :pointer if info.direction == :inout
77
+ return :pointer if info.direction == :out
148
78
  return itypeinfo_to_ffitype info.type
149
79
  end
150
80
 
@@ -154,14 +84,11 @@ module GirFFI
154
84
 
155
85
  sym = interface.name.to_sym
156
86
 
157
- # FIXME: Rescue is ugly here.
158
- ft = lib.find_type sym rescue nil
159
- if ft.nil?
87
+ optionally_define_constant modul, sym do
160
88
  args = ffi_function_argument_types interface
161
89
  ret = ffi_function_return_type interface
162
90
  lib.callback sym, args, ret
163
91
  end
164
- sym
165
92
  end
166
93
 
167
94
  # Set up method access.
@@ -169,7 +96,7 @@ module GirFFI
169
96
  private_class_method m.to_sym
170
97
  end
171
98
  public_class_method :build_module, :build_class
172
- public_class_method :setup_method, :setup_function, :setup_instance_method
173
99
  public_class_method :itypeinfo_to_ffitype
100
+ public_class_method :attach_ffi_function
174
101
  end
175
102
  end
@@ -1,6 +1,6 @@
1
1
  module GirFFI
2
2
  module BuilderHelper
3
- def self.const_defined_for parent, name
3
+ def const_defined_for parent, name
4
4
  if RUBY_VERSION < "1.9"
5
5
  parent.const_defined? name
6
6
  else
@@ -8,25 +8,12 @@ module GirFFI
8
8
  end
9
9
  end
10
10
 
11
- def self.optionally_define_constant parent, name
11
+ def optionally_define_constant parent, name
12
12
  unless const_defined_for parent, name
13
13
  parent.const_set name, yield
14
14
  end
15
15
  parent.const_get name
16
16
  end
17
17
 
18
- def self.get_or_define_module parent, name
19
- optionally_define_constant(parent, name) { Module.new }
20
- end
21
-
22
- def self.get_or_define_class namespace, name, parent
23
- BuilderHelper.optionally_define_constant namespace, name do
24
- if parent.nil?
25
- klass = Class.new
26
- else
27
- klass = Class.new parent
28
- end
29
- end
30
- end
31
18
  end
32
19
  end
@@ -0,0 +1,51 @@
1
+ require 'forwardable'
2
+ module GirFFI
3
+ # Base class for all generated classes. Contains code for dealing with
4
+ # the generated Struct classes.
5
+ class ClassBase
6
+ extend Forwardable
7
+ def_delegators :@struct, :[], :[]=, :to_ptr
8
+
9
+ def initialize(*args)
10
+ # TODO: Handle NULL pointer.
11
+ @struct = ffi_structure.new(*args)
12
+ end
13
+
14
+ def ffi_structure
15
+ self.class.ffi_structure
16
+ end
17
+
18
+ def gir_ffi_builder
19
+ self.class.gir_ffi_builder
20
+ end
21
+
22
+ def method_missing method, *arguments, &block
23
+ result = gir_ffi_builder.setup_instance_method method.to_s
24
+ return super unless result
25
+ self.send method, *arguments, &block
26
+ end
27
+
28
+ def self.method_missing method, *arguments, &block
29
+ result = gir_ffi_builder.setup_method method.to_s
30
+ return super unless result
31
+ self.send method, *arguments, &block
32
+ end
33
+
34
+ class << self
35
+ def ffi_structure
36
+ self.const_get(:Struct)
37
+ end
38
+
39
+ def gir_info
40
+ self.const_get :GIR_INFO
41
+ end
42
+
43
+ def gir_ffi_builder
44
+ self.const_get :GIR_FFI_BUILDER
45
+ end
46
+
47
+ alias_method :_real_new, :new
48
+ undef new
49
+ end
50
+ end
51
+ end