ffi-tk 2009.11.29
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +748 -0
- data/MANIFEST +188 -0
- data/README.md +85 -0
- data/Rakefile +47 -0
- data/TODO.md +62 -0
- data/bin/rwish +33 -0
- data/doc/MIT_LICENSE +18 -0
- data/doc/TCL_LICENSE +39 -0
- data/example/choose_color.rb +22 -0
- data/example/choose_directory.rb +22 -0
- data/example/dialog.rb +37 -0
- data/example/hello.rb +11 -0
- data/example/message_box.rb +26 -0
- data/example/option_menu.rb +17 -0
- data/example/popup.rb +24 -0
- data/example/set_palette.rb +32 -0
- data/example/text.rb +47 -0
- data/example/tile/kroc_demo_small.rb +123 -0
- data/example/tile/kroc_rb_demo.rb +135 -0
- data/example/tile/notebook.rb +48 -0
- data/example/tile/theme_hello.rb +38 -0
- data/example/tile/treeview.rb +71 -0
- data/example/various.rb +25 -0
- data/example/wait.rb +16 -0
- data/ffi-tk.gemspec +33 -0
- data/lib/ffi-tk.rb +76 -0
- data/lib/ffi-tk/command.rb +39 -0
- data/lib/ffi-tk/command/after.rb +36 -0
- data/lib/ffi-tk/command/bell.rb +34 -0
- data/lib/ffi-tk/command/bind.rb +11 -0
- data/lib/ffi-tk/command/bindtags.rb +69 -0
- data/lib/ffi-tk/command/cget.rb +92 -0
- data/lib/ffi-tk/command/choose_color.rb +29 -0
- data/lib/ffi-tk/command/choose_directory.rb +45 -0
- data/lib/ffi-tk/command/clipboard.rb +102 -0
- data/lib/ffi-tk/command/configure.rb +88 -0
- data/lib/ffi-tk/command/destroy.rb +12 -0
- data/lib/ffi-tk/command/dialog.rb +54 -0
- data/lib/ffi-tk/command/event.rb +79 -0
- data/lib/ffi-tk/command/focus.rb +70 -0
- data/lib/ffi-tk/command/font.rb +124 -0
- data/lib/ffi-tk/command/get_open_file.rb +85 -0
- data/lib/ffi-tk/command/get_save_file.rb +83 -0
- data/lib/ffi-tk/command/grab.rb +141 -0
- data/lib/ffi-tk/command/grid.rb +246 -0
- data/lib/ffi-tk/command/image.rb +79 -0
- data/lib/ffi-tk/command/lower.rb +23 -0
- data/lib/ffi-tk/command/message_box.rb +65 -0
- data/lib/ffi-tk/command/option_menu.rb +8 -0
- data/lib/ffi-tk/command/pack.rb +99 -0
- data/lib/ffi-tk/command/place.rb +91 -0
- data/lib/ffi-tk/command/popup.rb +14 -0
- data/lib/ffi-tk/command/raise.rb +25 -0
- data/lib/ffi-tk/command/scrollable.rb +151 -0
- data/lib/ffi-tk/command/selection.rb +132 -0
- data/lib/ffi-tk/command/set_palette.rb +9 -0
- data/lib/ffi-tk/command/tk_cmd.rb +155 -0
- data/lib/ffi-tk/command/vars.rb +82 -0
- data/lib/ffi-tk/command/wait.rb +39 -0
- data/lib/ffi-tk/command/winfo.rb +668 -0
- data/lib/ffi-tk/command/wm.rb +1025 -0
- data/lib/ffi-tk/core_extensions.rb +154 -0
- data/lib/ffi-tk/event/data.rb +60 -0
- data/lib/ffi-tk/event/handler.rb +44 -0
- data/lib/ffi-tk/ffi/tcl.rb +92 -0
- data/lib/ffi-tk/ffi/tcl/cmd_proc.rb +10 -0
- data/lib/ffi-tk/ffi/tcl/eval_result.rb +148 -0
- data/lib/ffi-tk/ffi/tcl/interp.rb +95 -0
- data/lib/ffi-tk/ffi/tcl/obj.rb +89 -0
- data/lib/ffi-tk/ffi/tcl/time.rb +36 -0
- data/lib/ffi-tk/ffi/tk.rb +35 -0
- data/lib/ffi-tk/geometry.rb +32 -0
- data/lib/ffi-tk/thread_sender.rb +26 -0
- data/lib/ffi-tk/tk.rb +222 -0
- data/lib/ffi-tk/variable.rb +46 -0
- data/lib/ffi-tk/widget.rb +68 -0
- data/lib/ffi-tk/widget/button.rb +41 -0
- data/lib/ffi-tk/widget/canvas.rb +806 -0
- data/lib/ffi-tk/widget/canvas/arc.rb +18 -0
- data/lib/ffi-tk/widget/canvas/bitmap.rb +13 -0
- data/lib/ffi-tk/widget/canvas/image.rb +10 -0
- data/lib/ffi-tk/widget/canvas/item.rb +170 -0
- data/lib/ffi-tk/widget/canvas/line.rb +16 -0
- data/lib/ffi-tk/widget/canvas/oval.rb +15 -0
- data/lib/ffi-tk/widget/canvas/polygon.rb +16 -0
- data/lib/ffi-tk/widget/canvas/rectangle.rb +15 -0
- data/lib/ffi-tk/widget/canvas/text.rb +15 -0
- data/lib/ffi-tk/widget/canvas/window.rb +11 -0
- data/lib/ffi-tk/widget/checkbutton.rb +63 -0
- data/lib/ffi-tk/widget/entry.rb +208 -0
- data/lib/ffi-tk/widget/frame.rb +12 -0
- data/lib/ffi-tk/widget/label.rb +26 -0
- data/lib/ffi-tk/widget/labelframe.rb +7 -0
- data/lib/ffi-tk/widget/listbox.rb +192 -0
- data/lib/ffi-tk/widget/menu.rb +318 -0
- data/lib/ffi-tk/widget/menubutton.rb +7 -0
- data/lib/ffi-tk/widget/message.rb +36 -0
- data/lib/ffi-tk/widget/panedwindow.rb +164 -0
- data/lib/ffi-tk/widget/radiobutton.rb +43 -0
- data/lib/ffi-tk/widget/root.rb +8 -0
- data/lib/ffi-tk/widget/scale.rb +44 -0
- data/lib/ffi-tk/widget/scrollbar.rb +114 -0
- data/lib/ffi-tk/widget/spinbox.rb +198 -0
- data/lib/ffi-tk/widget/text.rb +893 -0
- data/lib/ffi-tk/widget/text/peer.rb +10 -0
- data/lib/ffi-tk/widget/tile.rb +70 -0
- data/lib/ffi-tk/widget/tile/button.rb +8 -0
- data/lib/ffi-tk/widget/tile/checkbutton.rb +8 -0
- data/lib/ffi-tk/widget/tile/combobox.rb +43 -0
- data/lib/ffi-tk/widget/tile/entry.rb +8 -0
- data/lib/ffi-tk/widget/tile/frame.rb +13 -0
- data/lib/ffi-tk/widget/tile/label.rb +9 -0
- data/lib/ffi-tk/widget/tile/labelframe.rb +8 -0
- data/lib/ffi-tk/widget/tile/menubutton.rb +8 -0
- data/lib/ffi-tk/widget/tile/notebook.rb +93 -0
- data/lib/ffi-tk/widget/tile/panedwindow.rb +9 -0
- data/lib/ffi-tk/widget/tile/progressbar.rb +59 -0
- data/lib/ffi-tk/widget/tile/radiobutton.rb +8 -0
- data/lib/ffi-tk/widget/tile/scale.rb +8 -0
- data/lib/ffi-tk/widget/tile/scrollbar.rb +41 -0
- data/lib/ffi-tk/widget/tile/separator.rb +23 -0
- data/lib/ffi-tk/widget/tile/sizegrip.rb +24 -0
- data/lib/ffi-tk/widget/tile/style.rb +114 -0
- data/lib/ffi-tk/widget/tile/treeview.rb +414 -0
- data/lib/ffi-tk/widget/toplevel.rb +14 -0
- data/spec/ffi-tk/command/bindtags.rb +18 -0
- data/spec/ffi-tk/command/clipboard.rb +18 -0
- data/spec/ffi-tk/command/font.rb +67 -0
- data/spec/ffi-tk/command/grid.rb +6 -0
- data/spec/ffi-tk/command/image.rb +26 -0
- data/spec/ffi-tk/command/pack.rb +20 -0
- data/spec/ffi-tk/command/place.rb +20 -0
- data/spec/ffi-tk/command/selection.rb +13 -0
- data/spec/ffi-tk/command/vars.rb +32 -0
- data/spec/ffi-tk/command/winfo.rb +233 -0
- data/spec/ffi-tk/command/wm.rb +185 -0
- data/spec/ffi-tk/event.rb +95 -0
- data/spec/ffi-tk/tile/button.rb +51 -0
- data/spec/ffi-tk/tile/checkbutton.rb +13 -0
- data/spec/ffi-tk/tile/combobox.rb +65 -0
- data/spec/ffi-tk/tile/entry.rb +61 -0
- data/spec/ffi-tk/tile/frame.rb +65 -0
- data/spec/ffi-tk/tile/label.rb +17 -0
- data/spec/ffi-tk/tile/labelframe.rb +13 -0
- data/spec/ffi-tk/tile/menubutton.rb +13 -0
- data/spec/ffi-tk/tile/notebook.rb +103 -0
- data/spec/ffi-tk/tile/panedwindow.rb +13 -0
- data/spec/ffi-tk/tile/progressbar.rb +78 -0
- data/spec/ffi-tk/tile/radiobutton.rb +13 -0
- data/spec/ffi-tk/tile/scale.rb +13 -0
- data/spec/ffi-tk/tile/scrollbar.rb +43 -0
- data/spec/ffi-tk/tile/separator.rb +22 -0
- data/spec/ffi-tk/tile/sizegrip.rb +13 -0
- data/spec/ffi-tk/tile/style.rb +161 -0
- data/spec/ffi-tk/tile/treeview.rb +101 -0
- data/spec/ffi-tk/variable.rb +24 -0
- data/spec/ffi-tk/widget/button.rb +22 -0
- data/spec/ffi-tk/widget/canvas.rb +169 -0
- data/spec/ffi-tk/widget/checkbutton.rb +44 -0
- data/spec/ffi-tk/widget/entry.rb +155 -0
- data/spec/ffi-tk/widget/frame.rb +8 -0
- data/spec/ffi-tk/widget/label.rb +16 -0
- data/spec/ffi-tk/widget/labelframe.rb +12 -0
- data/spec/ffi-tk/widget/listbox.rb +19 -0
- data/spec/ffi-tk/widget/menu.rb +12 -0
- data/spec/ffi-tk/widget/menubutton.rb +12 -0
- data/spec/ffi-tk/widget/message.rb +12 -0
- data/spec/ffi-tk/widget/panedwindow.rb +12 -0
- data/spec/ffi-tk/widget/radiobutton.rb +12 -0
- data/spec/ffi-tk/widget/root.rb +9 -0
- data/spec/ffi-tk/widget/scale.rb +12 -0
- data/spec/ffi-tk/widget/scrollbar.rb +12 -0
- data/spec/ffi-tk/widget/spinbox.rb +12 -0
- data/spec/ffi-tk/widget/text.rb +246 -0
- data/spec/ffi-tk/widget/toplevel.rb +12 -0
- data/spec/helper.rb +3 -0
- data/tasks/authors.rake +21 -0
- data/tasks/bacon.rake +66 -0
- data/tasks/changelog.rake +18 -0
- data/tasks/gem.rake +22 -0
- data/tasks/gem_setup.rake +113 -0
- data/tasks/grancher.rake +12 -0
- data/tasks/manifest.rake +4 -0
- data/tasks/rcov.rake +17 -0
- data/tasks/release.rake +65 -0
- data/tasks/reversion.rake +8 -0
- data/tasks/setup.rake +12 -0
- data/tasks/ycov.rake +84 -0
- 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,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
|