gir_ffi 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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