mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
3db12e8b23
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
528 lines
10 KiB
Ruby
528 lines
10 KiB
Ruby
#
|
|
# tkcore.rb - Tk interface modue without thread
|
|
# $Date$
|
|
# by Yukihiro Matsumoto <matz@caelum.co.jp>
|
|
|
|
require "tkutil"
|
|
if defined? Thread
|
|
require "thread"
|
|
end
|
|
|
|
module Tk
|
|
include TkUtil
|
|
extend Tk
|
|
|
|
wish_path = nil
|
|
ENV['PATH'].split(":").each {|path|
|
|
for wish in ['wish4.2', 'wish4.1', 'wish4.0', 'wish']
|
|
if File.exist? path+'/'+wish
|
|
wish_path = path+'/'+wish
|
|
break
|
|
end
|
|
break if wish_path
|
|
end
|
|
}
|
|
fail 'can\'t find wish' if not wish_path #'
|
|
|
|
def Tk.tk_exit
|
|
if not PORT.closed?
|
|
PORT.print "exit\n"
|
|
PORT.close
|
|
end
|
|
end
|
|
|
|
# PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+");
|
|
PORT = open(format("|%s", wish_path), "w+");
|
|
trap "EXIT", proc{Tk.tk_exit}
|
|
trap "PIPE", ""
|
|
|
|
def tk_write(*args)
|
|
printf PORT, *args;
|
|
PORT.print "\n"
|
|
PORT.flush
|
|
end
|
|
tk_write '\
|
|
wm withdraw .
|
|
proc rb_out args {
|
|
puts [format %%s $args]
|
|
flush stdout
|
|
}
|
|
proc rb_ans arg {
|
|
if [catch $arg var] {puts "!$var"} {puts "=$var@@"}
|
|
flush stdout
|
|
}
|
|
proc tkerror args { exit }
|
|
proc keepalive {} { rb_out alive; after 120000 keepalive}
|
|
after 120000 keepalive'
|
|
|
|
READABLE = []
|
|
READ_CMD = {}
|
|
|
|
def file_readable(port, cmd)
|
|
if cmd == nil
|
|
READABLE.delete port
|
|
else
|
|
READABLE.push port
|
|
end
|
|
READ_CMD[port] = cmd
|
|
end
|
|
|
|
WRITABLE = []
|
|
WRITE_CMD = {}
|
|
def file_writable(port, cmd)
|
|
if cmd == nil
|
|
WRITABLE.delete port
|
|
else
|
|
WRITABLE.push port
|
|
end
|
|
WRITE_CMD[port] = cmd
|
|
end
|
|
module_function :file_readable, :file_writable
|
|
|
|
file_readable PORT, proc {
|
|
line = PORT.gets
|
|
exit if not line
|
|
Tk.dispatch(line.chop!)
|
|
}
|
|
|
|
def error_at
|
|
frames = caller(1)
|
|
frames.delete_if do |c|
|
|
c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+!
|
|
end
|
|
frames
|
|
end
|
|
|
|
def tk_tcl2ruby(val)
|
|
case val
|
|
when /^-?\d+$/
|
|
val.to_i
|
|
when /^\./
|
|
$tk_window_list[val]
|
|
when /^rb_out (c\d+)/
|
|
$tk_cmdtbl[$1]
|
|
when / /
|
|
val.split.collect{|elt|
|
|
tk_tcl2ruby(elt)
|
|
}
|
|
when /^-?\d+\.\d*$/
|
|
val.to_f
|
|
else
|
|
val
|
|
end
|
|
end
|
|
|
|
def tk_split_list(str)
|
|
idx = str.index('{')
|
|
return tk_tcl2ruby(str) if not idx
|
|
|
|
list = tk_tcl2ruby(str[0,idx])
|
|
str = str[idx+1..-1]
|
|
i = -1
|
|
brace = 1
|
|
str.each_byte {|c|
|
|
i += 1
|
|
brace += 1 if c == ?{
|
|
brace -= 1 if c == ?}
|
|
break if brace == 0
|
|
}
|
|
if str[0, i] == ' '
|
|
list.push ' '
|
|
else
|
|
list.push tk_split_list(str[0, i])
|
|
end
|
|
list += tk_split_list(str[i+1..-1])
|
|
list
|
|
end
|
|
private :tk_tcl2ruby, :tk_split_list
|
|
|
|
def bool(val)
|
|
case bool
|
|
when "1", 1, 'yes', 'true'
|
|
TRUE
|
|
else
|
|
FALSE
|
|
end
|
|
end
|
|
def number(val)
|
|
case val
|
|
when /^-?\d+$/
|
|
val.to_i
|
|
when /^-?\d+\.\d*$/
|
|
val.to_f
|
|
else
|
|
val
|
|
end
|
|
end
|
|
def string(val)
|
|
if val == "{}"
|
|
''
|
|
elsif val[0] == ?{
|
|
val[1..-2]
|
|
else
|
|
val
|
|
end
|
|
end
|
|
def list(val)
|
|
tk_split_list(val)
|
|
end
|
|
def window(val)
|
|
$tk_window_list[val]
|
|
end
|
|
def procedure(val)
|
|
if val =~ /^rb_out (c\d+)/
|
|
$tk_cmdtbl[$1]
|
|
else
|
|
nil
|
|
end
|
|
end
|
|
private :bool, :number, :string, :list, :window, :procedure
|
|
|
|
# mark for non-given arguments
|
|
None = Object.new
|
|
def None.to_s
|
|
'None'
|
|
end
|
|
|
|
$tk_event_queue = []
|
|
def tk_call(str, *args)
|
|
args = args.collect{|s|
|
|
next if s == None
|
|
if s.kind_of?(Hash)
|
|
s = hash_kv(s).join(" ")
|
|
else
|
|
if not s
|
|
s = "0"
|
|
elsif s == TRUE
|
|
s = "1"
|
|
elsif s.kind_of?(TkObject)
|
|
s = s.path
|
|
elsif s.kind_of?(TkVariable)
|
|
s = s.id
|
|
else
|
|
s = s.to_s
|
|
s.gsub!(/["\\\$\[\]]/, '\\\\\0') #"
|
|
s.gsub!(/\{/, '\\\\173')
|
|
s.gsub!(/\}/, '\\\\175')
|
|
end
|
|
"\"#{s}\""
|
|
end
|
|
}
|
|
str += " "
|
|
str += args.join(" ")
|
|
print str, "\n" if $DEBUG
|
|
tk_write 'rb_ans {%s}', str
|
|
while PORT.gets
|
|
print $_ if $DEBUG
|
|
$_.chop!
|
|
if /^=(.*)@@$/
|
|
val = $1
|
|
break
|
|
elsif /^=/
|
|
val = $' + "\n"
|
|
while TRUE
|
|
PORT.readline
|
|
if ~/@@$/
|
|
val += $'
|
|
return val
|
|
else
|
|
val += $_
|
|
end
|
|
end
|
|
elsif /^!/
|
|
$@ = error_at
|
|
msg = $'
|
|
if msg =~ /unknown option "-(.*)"/
|
|
$! = NameError.new(format("undefined method `%s' for %s(%s)",
|
|
$1, self, self.type)) #`'
|
|
else
|
|
$! = RuntimeError.new(format("%s - %s", self.type, msg))
|
|
end
|
|
fail
|
|
end
|
|
$tk_event_queue.push $_
|
|
end
|
|
|
|
while ev = $tk_event_queue.shift
|
|
Tk.dispatch ev
|
|
end
|
|
fail 'wish closed' if PORT.closed?
|
|
# tk_split_list(val)
|
|
val
|
|
end
|
|
|
|
def hash_kv(keys)
|
|
conf = []
|
|
if keys
|
|
for k, v in keys
|
|
conf.push("-#{k}")
|
|
v = install_cmd(v) if v.kind_of? Proc
|
|
conf.push(v)
|
|
end
|
|
end
|
|
conf
|
|
end
|
|
private :tk_call, :error_at, :hash_kv
|
|
|
|
$tk_cmdid = 0
|
|
def install_cmd(cmd)
|
|
return '' if cmd == '' # uninstall cmd
|
|
id = format("c%.4d", $tk_cmdid)
|
|
$tk_cmdid += 1
|
|
$tk_cmdtbl[id] = cmd
|
|
@cmdtbl = [] if not @cmdtbl
|
|
@cmdtbl.push id
|
|
return format('rb_out %s', id)
|
|
end
|
|
def uninstall_cmd(id)
|
|
$tk_cmdtbl[id] = nil
|
|
end
|
|
private :install_cmd, :uninstall_cmd
|
|
|
|
$tk_window_list = {}
|
|
class Event
|
|
def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy)
|
|
@serial = seq
|
|
@num = b
|
|
@focus = (f == 1)
|
|
@height = h
|
|
@keycode = k
|
|
@state = s
|
|
@time = t
|
|
@width = w
|
|
@x = x
|
|
@y = y
|
|
@char = aa
|
|
@send_event = (ee == 1)
|
|
@keysym = kk
|
|
@keysym_num = nn
|
|
@type = tt
|
|
@widget = ww
|
|
@x_root = xx
|
|
@y_root = yy
|
|
end
|
|
attr :serial
|
|
attr :num
|
|
attr :focus
|
|
attr :height
|
|
attr :keycode
|
|
attr :state
|
|
attr :time
|
|
attr :width
|
|
attr :x
|
|
attr :y
|
|
attr :char
|
|
attr :send_event
|
|
attr :keysym
|
|
attr :keysym_num
|
|
attr :type
|
|
attr :widget
|
|
attr :x_root
|
|
attr :y_root
|
|
end
|
|
|
|
def install_bind(cmd, args=nil)
|
|
if args
|
|
id = install_cmd(proc{|arg|
|
|
TkUtil.eval_cmd cmd, *arg
|
|
})
|
|
id + " " + args
|
|
else
|
|
id = install_cmd(proc{|arg|
|
|
TkUtil.eval_cmd cmd, Event.new(*arg)
|
|
})
|
|
id + " %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y"
|
|
end
|
|
end
|
|
|
|
def _bind(path, context, cmd, args=nil)
|
|
begin
|
|
id = install_bind(cmd, args)
|
|
tk_call 'bind', path, "<#{context}>", id
|
|
rescue
|
|
$tk_cmdtbl[id] = nil
|
|
fail
|
|
end
|
|
end
|
|
private :install_bind, :_bind
|
|
|
|
def bind_all(context, cmd=Proc.new, args=nil)
|
|
_bind 'all', context, cmd, args
|
|
end
|
|
|
|
def pack(*args)
|
|
TkPack.configure *args
|
|
end
|
|
|
|
$tk_cmdtbl = {}
|
|
|
|
def after(ms, cmd=Proc.new)
|
|
myid = format("c%.4d", $tk_cmdid)
|
|
tk_call 'after', ms,
|
|
install_cmd(proc{
|
|
TkUtil.eval_cmd cmd
|
|
uninstall_cmd myid
|
|
})
|
|
end
|
|
|
|
def update(idle=nil)
|
|
if idle
|
|
tk_call 'update', 'idletasks'
|
|
else
|
|
tk_call 'update'
|
|
end
|
|
end
|
|
|
|
def dispatch(line)
|
|
if line =~ /^c\d+/
|
|
cmd = $&
|
|
fail "no command `#{cmd}'" if not $tk_cmdtbl[cmd]
|
|
args = tk_split_list($')
|
|
TkUtil.eval_cmd $tk_cmdtbl[cmd], *args
|
|
elsif line =~ /^alive$/
|
|
# keep alive, do nothing
|
|
else
|
|
fail "malformed line <#{line}>"
|
|
end
|
|
end
|
|
|
|
def mainloop
|
|
begin
|
|
tk_write 'after idle {wm deiconify .}'
|
|
while TRUE
|
|
rf, wf = select(READABLE, WRITABLE)
|
|
for f in rf
|
|
READ_CMD[f].call(f) if READ_CMD[f]
|
|
if f.closed?
|
|
READABLE.delete f
|
|
READ_CMD[f] = nil
|
|
end
|
|
end
|
|
for f in wf
|
|
WRITE_CMD[f].call(f) if WRITE_CMD[f]
|
|
if f.closed?
|
|
WRITABLE.delete f
|
|
WRITE_CMD[f] = nil
|
|
end
|
|
end
|
|
end
|
|
ensure
|
|
Tk.tk_exit
|
|
end
|
|
end
|
|
|
|
def root
|
|
$tk_root
|
|
end
|
|
|
|
def bell
|
|
tk_call 'bell'
|
|
end
|
|
module_function :after, :update, :dispatch, :mainloop, :root, :bell
|
|
|
|
module Scrollable
|
|
def xscrollcommand(cmd=Proc.new)
|
|
configure_cmd 'xscrollcommand', cmd
|
|
end
|
|
def yscrollcommand(cmd=Proc.new)
|
|
configure_cmd 'yscrollcommand', cmd
|
|
end
|
|
end
|
|
|
|
module Wm
|
|
def aspect(*args)
|
|
w = window(tk_call('wm', 'grid', path, *args))
|
|
w.split.collect{|s|s.to_i} if args.length == 0
|
|
end
|
|
def client(name=None)
|
|
tk_call 'wm', 'client', path, name
|
|
end
|
|
def colormapwindows(*args)
|
|
list(tk_call('wm', 'colormapwindows', path, *args))
|
|
end
|
|
def wm_command(value=None)
|
|
string(tk_call('wm', 'command', path, value))
|
|
end
|
|
def deiconify
|
|
tk_call 'wm', 'deiconify', path
|
|
end
|
|
def focusmodel(*args)
|
|
tk_call 'wm', 'focusmodel', path, *args
|
|
end
|
|
def frame
|
|
tk_call 'wm', 'frame', path
|
|
end
|
|
def geometry(*args)
|
|
list(tk_call('wm', 'geometry', path, *args))
|
|
end
|
|
def grid(*args)
|
|
w = tk_call('wm', 'grid', path, *args)
|
|
list(w) if args.size == 0
|
|
end
|
|
def group(*args)
|
|
tk_call 'wm', 'path', path, *args
|
|
end
|
|
def iconbitmap(*args)
|
|
tk_call 'wm', 'bitmap', path, *args
|
|
end
|
|
def iconify
|
|
tk_call 'wm', 'iconify'
|
|
end
|
|
def iconmask(*args)
|
|
tk_call 'wm', 'iconmask', path, *args
|
|
end
|
|
def iconname(*args)
|
|
tk_call 'wm', 'iconname', path, *args
|
|
end
|
|
def iconposition(*args)
|
|
w = tk_call('wm', 'iconposition', path, *args)
|
|
list(w) if args.size == 0
|
|
end
|
|
def iconwindow(*args)
|
|
tk_call 'wm', 'iconwindow', path, *args
|
|
end
|
|
def maxsize(*args)
|
|
w = tk_call('wm', 'maxsize', path, *args)
|
|
list(w) if not args.size == 0
|
|
end
|
|
def minsize(*args)
|
|
w = tk_call('wm', 'minsize', path, *args)
|
|
list(w) if args.size == 0
|
|
end
|
|
def overrideredirect(bool=None)
|
|
if bool == None
|
|
bool(tk_call('wm', 'overrideredirect', path))
|
|
else
|
|
tk_call 'wm', 'overrideredirect', path, bool
|
|
end
|
|
end
|
|
def positionfrom(*args)
|
|
tk_call 'wm', 'positionfrom', path, *args
|
|
end
|
|
def protocol(name, func=None)
|
|
func = install_cmd(func) if not func == None
|
|
tk_call 'wm', 'command', path, name, func
|
|
end
|
|
def resizable(*args)
|
|
w = tk_call('wm', 'resizable', path, *args)
|
|
if args.length == 0
|
|
list(w).collect{|e| bool(e)}
|
|
end
|
|
end
|
|
def sizefrom(*args)
|
|
list(tk_call('wm', 'sizefrom', path, *args))
|
|
end
|
|
def state
|
|
tk_call 'wm', 'state', path
|
|
end
|
|
def title(*args)
|
|
tk_call 'wm', 'title', path, *args
|
|
end
|
|
def transient(*args)
|
|
tk_call 'wm', 'transient', path, *args
|
|
end
|
|
def withdraw
|
|
tk_call 'wm', 'withdraw', path
|
|
end
|
|
end
|
|
end
|