ffi-tk 2009.11.29

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 (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