ffi-tk 2009.11.29

Sign up to get free protection for your applications and to get access to all the features.
Files changed (189) hide show
  1. data/CHANGELOG +748 -0
  2. data/MANIFEST +188 -0
  3. data/README.md +85 -0
  4. data/Rakefile +47 -0
  5. data/TODO.md +62 -0
  6. data/bin/rwish +33 -0
  7. data/doc/MIT_LICENSE +18 -0
  8. data/doc/TCL_LICENSE +39 -0
  9. data/example/choose_color.rb +22 -0
  10. data/example/choose_directory.rb +22 -0
  11. data/example/dialog.rb +37 -0
  12. data/example/hello.rb +11 -0
  13. data/example/message_box.rb +26 -0
  14. data/example/option_menu.rb +17 -0
  15. data/example/popup.rb +24 -0
  16. data/example/set_palette.rb +32 -0
  17. data/example/text.rb +47 -0
  18. data/example/tile/kroc_demo_small.rb +123 -0
  19. data/example/tile/kroc_rb_demo.rb +135 -0
  20. data/example/tile/notebook.rb +48 -0
  21. data/example/tile/theme_hello.rb +38 -0
  22. data/example/tile/treeview.rb +71 -0
  23. data/example/various.rb +25 -0
  24. data/example/wait.rb +16 -0
  25. data/ffi-tk.gemspec +33 -0
  26. data/lib/ffi-tk.rb +76 -0
  27. data/lib/ffi-tk/command.rb +39 -0
  28. data/lib/ffi-tk/command/after.rb +36 -0
  29. data/lib/ffi-tk/command/bell.rb +34 -0
  30. data/lib/ffi-tk/command/bind.rb +11 -0
  31. data/lib/ffi-tk/command/bindtags.rb +69 -0
  32. data/lib/ffi-tk/command/cget.rb +92 -0
  33. data/lib/ffi-tk/command/choose_color.rb +29 -0
  34. data/lib/ffi-tk/command/choose_directory.rb +45 -0
  35. data/lib/ffi-tk/command/clipboard.rb +102 -0
  36. data/lib/ffi-tk/command/configure.rb +88 -0
  37. data/lib/ffi-tk/command/destroy.rb +12 -0
  38. data/lib/ffi-tk/command/dialog.rb +54 -0
  39. data/lib/ffi-tk/command/event.rb +79 -0
  40. data/lib/ffi-tk/command/focus.rb +70 -0
  41. data/lib/ffi-tk/command/font.rb +124 -0
  42. data/lib/ffi-tk/command/get_open_file.rb +85 -0
  43. data/lib/ffi-tk/command/get_save_file.rb +83 -0
  44. data/lib/ffi-tk/command/grab.rb +141 -0
  45. data/lib/ffi-tk/command/grid.rb +246 -0
  46. data/lib/ffi-tk/command/image.rb +79 -0
  47. data/lib/ffi-tk/command/lower.rb +23 -0
  48. data/lib/ffi-tk/command/message_box.rb +65 -0
  49. data/lib/ffi-tk/command/option_menu.rb +8 -0
  50. data/lib/ffi-tk/command/pack.rb +99 -0
  51. data/lib/ffi-tk/command/place.rb +91 -0
  52. data/lib/ffi-tk/command/popup.rb +14 -0
  53. data/lib/ffi-tk/command/raise.rb +25 -0
  54. data/lib/ffi-tk/command/scrollable.rb +151 -0
  55. data/lib/ffi-tk/command/selection.rb +132 -0
  56. data/lib/ffi-tk/command/set_palette.rb +9 -0
  57. data/lib/ffi-tk/command/tk_cmd.rb +155 -0
  58. data/lib/ffi-tk/command/vars.rb +82 -0
  59. data/lib/ffi-tk/command/wait.rb +39 -0
  60. data/lib/ffi-tk/command/winfo.rb +668 -0
  61. data/lib/ffi-tk/command/wm.rb +1025 -0
  62. data/lib/ffi-tk/core_extensions.rb +154 -0
  63. data/lib/ffi-tk/event/data.rb +60 -0
  64. data/lib/ffi-tk/event/handler.rb +44 -0
  65. data/lib/ffi-tk/ffi/tcl.rb +92 -0
  66. data/lib/ffi-tk/ffi/tcl/cmd_proc.rb +10 -0
  67. data/lib/ffi-tk/ffi/tcl/eval_result.rb +148 -0
  68. data/lib/ffi-tk/ffi/tcl/interp.rb +95 -0
  69. data/lib/ffi-tk/ffi/tcl/obj.rb +89 -0
  70. data/lib/ffi-tk/ffi/tcl/time.rb +36 -0
  71. data/lib/ffi-tk/ffi/tk.rb +35 -0
  72. data/lib/ffi-tk/geometry.rb +32 -0
  73. data/lib/ffi-tk/thread_sender.rb +26 -0
  74. data/lib/ffi-tk/tk.rb +222 -0
  75. data/lib/ffi-tk/variable.rb +46 -0
  76. data/lib/ffi-tk/widget.rb +68 -0
  77. data/lib/ffi-tk/widget/button.rb +41 -0
  78. data/lib/ffi-tk/widget/canvas.rb +806 -0
  79. data/lib/ffi-tk/widget/canvas/arc.rb +18 -0
  80. data/lib/ffi-tk/widget/canvas/bitmap.rb +13 -0
  81. data/lib/ffi-tk/widget/canvas/image.rb +10 -0
  82. data/lib/ffi-tk/widget/canvas/item.rb +170 -0
  83. data/lib/ffi-tk/widget/canvas/line.rb +16 -0
  84. data/lib/ffi-tk/widget/canvas/oval.rb +15 -0
  85. data/lib/ffi-tk/widget/canvas/polygon.rb +16 -0
  86. data/lib/ffi-tk/widget/canvas/rectangle.rb +15 -0
  87. data/lib/ffi-tk/widget/canvas/text.rb +15 -0
  88. data/lib/ffi-tk/widget/canvas/window.rb +11 -0
  89. data/lib/ffi-tk/widget/checkbutton.rb +63 -0
  90. data/lib/ffi-tk/widget/entry.rb +208 -0
  91. data/lib/ffi-tk/widget/frame.rb +12 -0
  92. data/lib/ffi-tk/widget/label.rb +26 -0
  93. data/lib/ffi-tk/widget/labelframe.rb +7 -0
  94. data/lib/ffi-tk/widget/listbox.rb +192 -0
  95. data/lib/ffi-tk/widget/menu.rb +318 -0
  96. data/lib/ffi-tk/widget/menubutton.rb +7 -0
  97. data/lib/ffi-tk/widget/message.rb +36 -0
  98. data/lib/ffi-tk/widget/panedwindow.rb +164 -0
  99. data/lib/ffi-tk/widget/radiobutton.rb +43 -0
  100. data/lib/ffi-tk/widget/root.rb +8 -0
  101. data/lib/ffi-tk/widget/scale.rb +44 -0
  102. data/lib/ffi-tk/widget/scrollbar.rb +114 -0
  103. data/lib/ffi-tk/widget/spinbox.rb +198 -0
  104. data/lib/ffi-tk/widget/text.rb +893 -0
  105. data/lib/ffi-tk/widget/text/peer.rb +10 -0
  106. data/lib/ffi-tk/widget/tile.rb +70 -0
  107. data/lib/ffi-tk/widget/tile/button.rb +8 -0
  108. data/lib/ffi-tk/widget/tile/checkbutton.rb +8 -0
  109. data/lib/ffi-tk/widget/tile/combobox.rb +43 -0
  110. data/lib/ffi-tk/widget/tile/entry.rb +8 -0
  111. data/lib/ffi-tk/widget/tile/frame.rb +13 -0
  112. data/lib/ffi-tk/widget/tile/label.rb +9 -0
  113. data/lib/ffi-tk/widget/tile/labelframe.rb +8 -0
  114. data/lib/ffi-tk/widget/tile/menubutton.rb +8 -0
  115. data/lib/ffi-tk/widget/tile/notebook.rb +93 -0
  116. data/lib/ffi-tk/widget/tile/panedwindow.rb +9 -0
  117. data/lib/ffi-tk/widget/tile/progressbar.rb +59 -0
  118. data/lib/ffi-tk/widget/tile/radiobutton.rb +8 -0
  119. data/lib/ffi-tk/widget/tile/scale.rb +8 -0
  120. data/lib/ffi-tk/widget/tile/scrollbar.rb +41 -0
  121. data/lib/ffi-tk/widget/tile/separator.rb +23 -0
  122. data/lib/ffi-tk/widget/tile/sizegrip.rb +24 -0
  123. data/lib/ffi-tk/widget/tile/style.rb +114 -0
  124. data/lib/ffi-tk/widget/tile/treeview.rb +414 -0
  125. data/lib/ffi-tk/widget/toplevel.rb +14 -0
  126. data/spec/ffi-tk/command/bindtags.rb +18 -0
  127. data/spec/ffi-tk/command/clipboard.rb +18 -0
  128. data/spec/ffi-tk/command/font.rb +67 -0
  129. data/spec/ffi-tk/command/grid.rb +6 -0
  130. data/spec/ffi-tk/command/image.rb +26 -0
  131. data/spec/ffi-tk/command/pack.rb +20 -0
  132. data/spec/ffi-tk/command/place.rb +20 -0
  133. data/spec/ffi-tk/command/selection.rb +13 -0
  134. data/spec/ffi-tk/command/vars.rb +32 -0
  135. data/spec/ffi-tk/command/winfo.rb +233 -0
  136. data/spec/ffi-tk/command/wm.rb +185 -0
  137. data/spec/ffi-tk/event.rb +95 -0
  138. data/spec/ffi-tk/tile/button.rb +51 -0
  139. data/spec/ffi-tk/tile/checkbutton.rb +13 -0
  140. data/spec/ffi-tk/tile/combobox.rb +65 -0
  141. data/spec/ffi-tk/tile/entry.rb +61 -0
  142. data/spec/ffi-tk/tile/frame.rb +65 -0
  143. data/spec/ffi-tk/tile/label.rb +17 -0
  144. data/spec/ffi-tk/tile/labelframe.rb +13 -0
  145. data/spec/ffi-tk/tile/menubutton.rb +13 -0
  146. data/spec/ffi-tk/tile/notebook.rb +103 -0
  147. data/spec/ffi-tk/tile/panedwindow.rb +13 -0
  148. data/spec/ffi-tk/tile/progressbar.rb +78 -0
  149. data/spec/ffi-tk/tile/radiobutton.rb +13 -0
  150. data/spec/ffi-tk/tile/scale.rb +13 -0
  151. data/spec/ffi-tk/tile/scrollbar.rb +43 -0
  152. data/spec/ffi-tk/tile/separator.rb +22 -0
  153. data/spec/ffi-tk/tile/sizegrip.rb +13 -0
  154. data/spec/ffi-tk/tile/style.rb +161 -0
  155. data/spec/ffi-tk/tile/treeview.rb +101 -0
  156. data/spec/ffi-tk/variable.rb +24 -0
  157. data/spec/ffi-tk/widget/button.rb +22 -0
  158. data/spec/ffi-tk/widget/canvas.rb +169 -0
  159. data/spec/ffi-tk/widget/checkbutton.rb +44 -0
  160. data/spec/ffi-tk/widget/entry.rb +155 -0
  161. data/spec/ffi-tk/widget/frame.rb +8 -0
  162. data/spec/ffi-tk/widget/label.rb +16 -0
  163. data/spec/ffi-tk/widget/labelframe.rb +12 -0
  164. data/spec/ffi-tk/widget/listbox.rb +19 -0
  165. data/spec/ffi-tk/widget/menu.rb +12 -0
  166. data/spec/ffi-tk/widget/menubutton.rb +12 -0
  167. data/spec/ffi-tk/widget/message.rb +12 -0
  168. data/spec/ffi-tk/widget/panedwindow.rb +12 -0
  169. data/spec/ffi-tk/widget/radiobutton.rb +12 -0
  170. data/spec/ffi-tk/widget/root.rb +9 -0
  171. data/spec/ffi-tk/widget/scale.rb +12 -0
  172. data/spec/ffi-tk/widget/scrollbar.rb +12 -0
  173. data/spec/ffi-tk/widget/spinbox.rb +12 -0
  174. data/spec/ffi-tk/widget/text.rb +246 -0
  175. data/spec/ffi-tk/widget/toplevel.rb +12 -0
  176. data/spec/helper.rb +3 -0
  177. data/tasks/authors.rake +21 -0
  178. data/tasks/bacon.rake +66 -0
  179. data/tasks/changelog.rake +18 -0
  180. data/tasks/gem.rake +22 -0
  181. data/tasks/gem_setup.rake +113 -0
  182. data/tasks/grancher.rake +12 -0
  183. data/tasks/manifest.rake +4 -0
  184. data/tasks/rcov.rake +17 -0
  185. data/tasks/release.rake +65 -0
  186. data/tasks/reversion.rake +8 -0
  187. data/tasks/setup.rake +12 -0
  188. data/tasks/ycov.rake +84 -0
  189. metadata +261 -0
@@ -0,0 +1,154 @@
1
+ module Tk
2
+ # Already converted statement, don't process again
3
+ class TclString < String
4
+ def to_tcl
5
+ self
6
+ end
7
+ end
8
+
9
+ # A lot of conversion helpers...
10
+
11
+ module CoreExtensions
12
+ module Array
13
+ def to_tcl
14
+ TclString.new('{' << map(&:to_tcl).compact.join(' ') << '}')
15
+ end
16
+
17
+ def tcl_options_to_hash(hints = {})
18
+ ::Hash[each_slice(2).map{|key, value|
19
+ key = key.sub(/^-/, '').to_sym
20
+
21
+ case hint = hints[key]
22
+ when :boolean
23
+ [key, Tk.boolean(value)]
24
+ when :symbol
25
+ [key, value.to_sym]
26
+ when :float
27
+ [key, Float(value)]
28
+ else
29
+ [key, value]
30
+ end
31
+ }]
32
+ end
33
+ end
34
+
35
+ module Hash
36
+ def to_tcl
37
+ pairs = map{|key, val| "#{key.to_tcl} #{val.to_tcl}" }
38
+ TclString.new(pairs.join(' '))
39
+ end
40
+
41
+ def to_tcl_options
42
+ pairs = map{|key, val| "#{key.to_tcl_option} #{val.to_tcl}" }
43
+ TclString.new(pairs.join(' '))
44
+ end
45
+ alias to_tcl_options? to_tcl_options
46
+ end
47
+
48
+ module Proc
49
+ def to_tcl
50
+ @id, @command = Tk.register_proc(self)
51
+ @command.to_tcl
52
+ end
53
+ end
54
+
55
+ module Regexp
56
+ def to_tcl
57
+ embed = []
58
+ embed << 'i' if options & ::Regexp::IGNORECASE != 0
59
+ embed << 'x' if options & ::Regexp::EXTENDED != 0
60
+ embed << 'n' if options & ::Regexp::MULTILINE != 0
61
+
62
+ if embed.empty?
63
+ pattern = source
64
+ else
65
+ pattern = "(?#{embed.join})#{source}"
66
+ end
67
+
68
+ TclString.new('{' << pattern.gsub(/([^\\])(?=[{}])/, '\1\\\\\2') << '}')
69
+ end
70
+ end
71
+
72
+ module String
73
+ def to_tcl
74
+ TclString.new('"' << gsub(/[\[\]$"\\]/, '\\\\\&') << '"')
75
+ end
76
+
77
+ def to_tcl_option
78
+ TclString.new(sub(/\A(?=[^-])/, '-'))
79
+ end
80
+ end
81
+
82
+ module Symbol
83
+ def to_tcl
84
+ TclString.new(to_s.dump)
85
+ end
86
+
87
+ def to_tcl_option
88
+ TclString.new(to_s.sub(/\A(?=[^-])/, '-'))
89
+ end
90
+ end
91
+
92
+ module Numeric
93
+ def to_tcl
94
+ TclString.new(to_s)
95
+ end
96
+ end
97
+
98
+ module Float
99
+ def tcl_to_ruby(option, hints)
100
+ self
101
+ end
102
+ end
103
+
104
+ module Fixnum
105
+ def tcl_to_ruby(option, hints)
106
+ name = option.sub(/^-/, '').to_sym
107
+
108
+ if type = hints[name]
109
+ case type
110
+ when :boolean
111
+ Tk.boolean(self)
112
+ else
113
+ self
114
+ end
115
+ end
116
+ end
117
+
118
+ def to_boolean
119
+ Tk.boolean(self)
120
+ end
121
+ end
122
+
123
+ module TrueClass
124
+ def to_tcl
125
+ TclString.new('1')
126
+ end
127
+ end
128
+
129
+ module FalseClass
130
+ def to_tcl
131
+ TclString.new('0')
132
+ end
133
+ end
134
+
135
+ module NilClass
136
+ def to_tcl
137
+ TclString.new('""')
138
+ end
139
+ end
140
+
141
+ constants.each do |const|
142
+ ext = const_get(const)
143
+ into = Module.const_get(const)
144
+
145
+ collisions = ext.instance_methods & into.instance_methods
146
+
147
+ if collisions.empty?
148
+ into.__send__(:include, ext)
149
+ else
150
+ warn "Won't include %p with %p, %p exists" % [into, ext, collisions] if $DEBBUG
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,60 @@
1
+ module Tk
2
+ module Event
3
+ Data = Struct.new(
4
+ :id, :sequence, :border_width, :button, :count, :detail, :focus, :height,
5
+ :keycode, :keysym, :keysym_number, :mode, :mousewheel_delta,
6
+ :override_redirect, :place, :property, :root, :send_event, :serial, :state,
7
+ :subwindow, :time, :type, :unicode, :width, :window, :window_path, :x,
8
+ :x_root, :y, :y_root
9
+ )
10
+
11
+ class Data
12
+ PROPERTIES = [
13
+ ['%#', :Integer, :serial ],
14
+ ['%b', :Integer, :button ],
15
+ ['%c', :Integer, :count ],
16
+ ['%d', :String, :detail ],
17
+ ['%f', :String, :focus ],
18
+ ['%h', :Integer, :height ],
19
+ ['%i', :String, :window ],
20
+ ['%k', :String, :keycode ],
21
+ ['%m', :String, :mode ],
22
+ ['%o', :String, :override_redirect ],
23
+ ['%p', :String, :place ],
24
+ ['%s', :String, :state ],
25
+ ['%t', :String, :time ],
26
+ ['%w', :Integer, :width ],
27
+ ['%x', :Integer, :x ],
28
+ ['%y', :Integer, :y ],
29
+ ['%A', :String, :unicode ],
30
+ ['%B', :Integer, :border_width ],
31
+ ['%D', :String, :mousewheel_delta ],
32
+ ['%E', :String, :send_event ],
33
+ ['%K', :String, :keysym ],
34
+ ['%N', :String, :keysym_number ],
35
+ ['%P', :String, :property ],
36
+ ['%R', :Integer, :root ],
37
+ ['%S', :Integer, :subwindow ],
38
+ ['%T', :Integer, :type ],
39
+ ['%W', :String, :window_path ],
40
+ ['%X', :Integer, :x_root ],
41
+ ['%Y', :Integer, :y_root ],
42
+ ]
43
+
44
+ def initialize(id, sequence, *properties)
45
+ super id, sequence
46
+
47
+ PROPERTIES.each do |code, conv, name|
48
+ property = properties.shift
49
+ next if property == '??'
50
+ converted = __send__(conv, property)
51
+ self[name] = converted
52
+ end
53
+ end
54
+
55
+ def call
56
+ Handler.invoke(id, self) if id
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,44 @@
1
+ module Tk
2
+ module Event
3
+ module Handler
4
+ data = Data::PROPERTIES.transpose[0].join(' ').gsub(/%/, '%%')
5
+ @callback = %(bind %s %s { ::RubyFFI::event %d %s #{data} })
6
+ @store = []
7
+ @mutex = Mutex.new
8
+
9
+ module_function
10
+
11
+ def invoke(id, event)
12
+ return unless found = @store.at(id)
13
+ found.call(event)
14
+ end
15
+
16
+ def register_block(block)
17
+ id = nil
18
+
19
+ @mutex.synchronize{
20
+ @store << block
21
+ id = @store.size - 1
22
+ }
23
+
24
+ return id
25
+ end
26
+
27
+ def register(tag, sequence, &block)
28
+ id = register_block(block)
29
+ Tk.interp.eval(@callback % [tag, sequence, id, sequence])
30
+ id
31
+ end
32
+
33
+ def register_custom(block)
34
+ id = register_block(block)
35
+ yield id
36
+ id
37
+ end
38
+
39
+ def unregister(id)
40
+ @store[id] = nil
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,92 @@
1
+ require 'ffi-tk/ffi/tcl/obj'
2
+ require 'ffi-tk/ffi/tcl/interp'
3
+ require 'ffi-tk/ffi/tcl/cmd_proc'
4
+ require 'ffi-tk/ffi/tcl/time'
5
+ require 'ffi-tk/ffi/tcl/eval_result'
6
+
7
+ module FFI
8
+ module Tcl
9
+ extend FFI::Library
10
+ ffi_lib 'libtcl8.5.so', 'tcl85.dll', *::Tk::LIBPATH[:tcl]
11
+
12
+ attach_function :Tcl_AppendAllObjTypes, [Interp, Obj], :int
13
+ attach_function :Tcl_CreateInterp, [], Interp
14
+ attach_function :Tcl_DeleteInterp, [Interp], :void
15
+ attach_function :Tcl_DoOneEvent, [flags = :int], :int
16
+ attach_function :Tcl_EvalEx, [Interp, script = :string, length = :int, flags = :int], :int
17
+ attach_function :Tcl_GetBoolean, [Interp, :string, :pointer], :int
18
+ attach_function :Tcl_GetBooleanFromObj, [Interp, Obj, boolean = :pointer], :int
19
+ attach_function :Tcl_GetDoubleFromObj, [Interp, Obj, :pointer], :int
20
+ attach_function :Tcl_GetIntFromObj, [Interp, Obj, int = :pointer], :int
21
+ attach_function :Tcl_GetObjResult, [Interp], Obj
22
+ attach_function :Tcl_GetObjType, [:string], ObjType
23
+ attach_function :Tcl_GetString, [Obj], :string
24
+ attach_function :Tcl_GetStringFromObj, [Obj, length = :pointer], :string
25
+ attach_function :Tcl_GetStringResult, [Interp], :string
26
+ attach_function :Tcl_GetUnicode, [Obj], :string
27
+ attach_function :Tcl_Init, [Interp], :int
28
+ attach_function :Tcl_ListObjGetElements, [Interp, Obj, count = :pointer, list = :pointer], :int
29
+ attach_function :Tcl_ListObjIndex, [Interp, list = :pointer, index = :int, result = :pointer], :int
30
+ attach_function :Tcl_ListObjLength, [Interp, list = :pointer, int = :pointer], :int
31
+ attach_function :Tcl_NewBooleanObj, [:int], Obj
32
+ attach_function :Tcl_NewIntObj, [:int], Obj
33
+ attach_function :Tcl_NewListObj, [count = :int, values = :pointer], Obj
34
+ attach_function :Tcl_NewStringObj, [:string, :int], Obj
35
+ attach_function :Tcl_ObjGetVar2, [Interp, :pointer, :pointer, :int], Obj
36
+ attach_function :Tcl_ObjSetVar2, [Interp, Obj, Obj, Obj, :int], Obj
37
+ attach_function :Tcl_ParseVar, [Interp, :pointer, :pointer], :pointer
38
+ attach_function :Tcl_SetObjResult, [Interp, Obj], :void
39
+ attach_function :Tcl_WaitForEvent, [TclTime], :int
40
+
41
+ callback :obj_cmd_proc, [:int, Interp, :int, :pointer], :int
42
+ callback :obj_delete_proc, [:int], :void
43
+ attach_function :Tcl_CreateObjCommand, [
44
+ Interp, name = :string, :obj_cmd_proc, :int, :obj_delete_proc], :pointer
45
+
46
+ module_function
47
+
48
+ ATTACHED_FUNCTIONS = {}
49
+ singleton_methods.grep(/^Tcl_/).each do |function|
50
+ ruby_name = function.to_s.
51
+ gsub(/([A-Z][a-z]+)/, '_\1').sub('_Tcl__', '').downcase
52
+ ATTACHED_FUNCTIONS[function] = ruby_name
53
+ end
54
+ BINDING = binding
55
+
56
+ def setup_eventloop_on_new_thread
57
+ puts "Run eventloop on new thread" if $DEBUG
58
+
59
+ code = <<-RUBY.strip
60
+ def self.%s(*args, &block)
61
+ @thread_sender.thread_send{ %s(*args, &block) }
62
+ end
63
+ RUBY
64
+
65
+ binding, file, line = BINDING, __FILE__, __LINE__ - 5
66
+ ATTACHED_FUNCTIONS.each do |function, ruby_name|
67
+ eval(code % [ruby_name, function], binding, file, line)
68
+ end
69
+
70
+ @thread_sender = ThreadSender.new
71
+ class << self; attr_reader :thread_sender; end
72
+ @thread_sender.thread_send{ Interp.new(create_interp) }
73
+ end
74
+
75
+ def setup_eventloop_on_main_thread
76
+ puts "Run eventloop on main thread" if $DEBUG
77
+
78
+ code = <<-'RUBY'.strip
79
+ def self.%s(*args, &block)
80
+ %s(*args, &block)
81
+ end
82
+ RUBY
83
+
84
+ binding, file, line = BINDING, __FILE__, __LINE__ - 5
85
+ ATTACHED_FUNCTIONS.each do |function, ruby_name|
86
+ eval(code % [ruby_name, function], binding, file, line)
87
+ end
88
+
89
+ Interp.new(create_interp)
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,10 @@
1
+ module FFI
2
+ module Tcl
3
+ class CmdProc < PrettyStruct
4
+ layout :clientData, :int,
5
+ :interp, Interp,
6
+ :argc, :int,
7
+ :argv, :pointer
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,148 @@
1
+ module FFI
2
+ module Tcl
3
+ # This whole class feels very awkward, maybe it should be merged with Obj.
4
+ class EvalResult < ::Struct.new(:interp, :obj)
5
+ TYPES = {}
6
+
7
+ def self.reset_types(interp)
8
+ TYPES.clear
9
+ list = Tcl.new_list_obj(0, nil)
10
+ Tcl.append_all_obj_types(interp, list)
11
+
12
+ result_pointer = MemoryPointer.new(:pointer)
13
+ count_pointer = MemoryPointer.new(:int)
14
+ length_pointer = MemoryPointer.new(:int)
15
+
16
+ Tcl.list_obj_length(interp, list, count_pointer)
17
+ count = count_pointer.get_int(0)
18
+
19
+ (0...count).each do |idx|
20
+ Tcl.list_obj_index(interp, list, idx, result_pointer)
21
+ element_pointer = result_pointer.get_pointer(0)
22
+ name = Tcl.get_string_from_obj(element_pointer, length_pointer)
23
+ type = Tcl.get_obj_type(name)
24
+ TYPES[type.to_i] = name.to_sym
25
+ end
26
+ end
27
+
28
+ def self.guess(interp, obj, fallback = nil)
29
+ obj = Obj.new(obj) unless obj.respond_to?(:type)
30
+ type = TYPES[obj.type.to_i]
31
+
32
+ case type
33
+ when :list
34
+ to_list(interp, obj)
35
+ when :string, :pixel, :cmdName
36
+ to_string(interp, obj)
37
+ when :int
38
+ to_int(interp, obj)
39
+ when :double
40
+ to_double(interp, obj)
41
+ else
42
+ if fallback
43
+ __send__(fallback, interp, obj)
44
+ else
45
+ raise "Unknown type: %p" % [type] if type
46
+ new(interp, obj)
47
+ end
48
+ end
49
+ end
50
+
51
+ def self.to_double(interp, obj)
52
+ double_pointer = MemoryPointer.new(:double)
53
+
54
+ if Tcl.get_double_from_obj(interp, obj, double_pointer) == 0
55
+ double_pointer.get_double(0)
56
+ else
57
+ raise "Couldn't get double from %p" % [obj]
58
+ end
59
+ end
60
+
61
+ def self.to_list(interp, obj)
62
+ map_list_core(interp, obj) do |pointer|
63
+ value = guess(interp, pointer, :to_string)
64
+ block_given? ? yield(value) : value
65
+ end
66
+ end
67
+
68
+ def self.map_list_core(interp, obj)
69
+ result_pointer = MemoryPointer.new(:pointer)
70
+ count_pointer = MemoryPointer.new(:int)
71
+ length_pointer = MemoryPointer.new(:int)
72
+
73
+ Tcl.list_obj_length(interp, obj, count_pointer)
74
+ count = count_pointer.get_int(0)
75
+
76
+ (0...count).map do |idx|
77
+ Tcl.list_obj_index(interp, obj, idx, result_pointer)
78
+ yield result_pointer.get_pointer(0)
79
+ end
80
+ end
81
+
82
+ def self.to_boolean(interp, obj)
83
+ boolean_pointer = MemoryPointer.new(:int)
84
+ Tcl.get_boolean_from_obj(interp, obj, boolean_pointer)
85
+ boolean_pointer.get_int(0) == 1
86
+ end
87
+
88
+ def self.to_int(interp, obj)
89
+ int_pointer = MemoryPointer.new(:int)
90
+ Tcl.get_int_from_obj(interp, obj, int_pointer)
91
+ int_pointer.get_int(0)
92
+ end
93
+
94
+ def self.to_string(interp, obj)
95
+ length_pointer = MemoryPointer.new(:int)
96
+ string = Tcl.get_string_from_obj(obj, length_pointer)
97
+ string.force_encoding(Encoding.default_external)
98
+ end
99
+
100
+ def to_a(&block)
101
+ self.class.to_list(interp, obj, &block)
102
+ end
103
+
104
+ def to_a?(&block)
105
+ value = self.class.to_list(interp, obj, &block)
106
+ value.empty? ? nil : value
107
+ end
108
+
109
+ def to_sym
110
+ self.class.to_string(interp, obj).to_sym
111
+ end
112
+
113
+ def to_sym?
114
+ value = self.class.to_string(interp, obj).to_sym
115
+ value.empty? ? nil : value.to_sym
116
+ end
117
+
118
+ def to_i
119
+ self.class.to_int(interp, obj)
120
+ end
121
+
122
+ def to_f
123
+ self.class.to_double(interp, obj)
124
+ end
125
+
126
+ def to_s
127
+ self.class.to_string(interp, obj)
128
+ end
129
+
130
+ def to_s?
131
+ value = self.class.to_string(interp, obj)
132
+ value.empty? ? nil : value
133
+ end
134
+
135
+ def to_boolean
136
+ self.class.to_boolean(interp, obj)
137
+ end
138
+
139
+ def to_tcl
140
+ to_s.to_tcl
141
+ end
142
+
143
+ def inspect
144
+ "#<EvalResult #{to_s}>"
145
+ end
146
+ end
147
+ end
148
+ end