1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/lib/tkcore.rb
matz 3db12e8b23 Initial revision
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1998-01-16 12:13:05 +00:00

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