mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* ext/tk/tcltklib.c: make SEGV risk lower at exit.
* ext/tk/lib/tk.rb: ditto. * ext/tk/lib/multi-tk.rb: fail to call function-style methods on slave interpreters. The strategy (MultiTkIp_PseudoToplevel_Evaluable) to fix the problem is a little tricky. You may have to take care of conflicting with it. * ext/tk/lib/tk.rb: a little change for the pseudo-toplevel strategy. * ext/tk/lib/tk/font.rb: ditto. * ext/tk/lib/tk/msgcat.rb: ditto. * ext/tk/lib/tkextlib/itk/incr_tk.rb: ditto. * ext/tk/sample/demos-en/widget: fail to call function-style methods on sample scripts. To fix it, a strategy which similar to the way on MultiTiIp is used. Please take care when re-write and re-run a demo script on the Widget-Demo code viewer. * ext/tk/sample/demos-jp/widget: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10505 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
a1a07fbfa1
commit
d2271cbdd1
9 changed files with 543 additions and 40 deletions
26
ChangeLog
26
ChangeLog
|
@ -1,3 +1,29 @@
|
||||||
|
Mon Jul 10 18:46:52 2006 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
|
||||||
|
|
||||||
|
* ext/tk/tcltklib.c: make SEGV risk lower at exit.
|
||||||
|
|
||||||
|
* ext/tk/lib/tk.rb: ditto.
|
||||||
|
|
||||||
|
* ext/tk/lib/multi-tk.rb: fail to call function-style methods on slave
|
||||||
|
interpreters. The strategy (MultiTkIp_PseudoToplevel_Evaluable) to
|
||||||
|
fix the problem is a little tricky. You may have to take care of
|
||||||
|
conflicting with it.
|
||||||
|
|
||||||
|
* ext/tk/lib/tk.rb: a little change for the pseudo-toplevel strategy.
|
||||||
|
|
||||||
|
* ext/tk/lib/tk/font.rb: ditto.
|
||||||
|
|
||||||
|
* ext/tk/lib/tk/msgcat.rb: ditto.
|
||||||
|
|
||||||
|
* ext/tk/lib/tkextlib/itk/incr_tk.rb: ditto.
|
||||||
|
|
||||||
|
* ext/tk/sample/demos-en/widget: fail to call function-style methods
|
||||||
|
on sample scripts. To fix it, a strategy which similar to the way
|
||||||
|
on MultiTiIp is used. Please take care when re-write and re-run a
|
||||||
|
demo script on the Widget-Demo code viewer.
|
||||||
|
|
||||||
|
* ext/tk/sample/demos-jp/widget: ditto.
|
||||||
|
|
||||||
Mon Jul 10 17:32:38 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
|
Mon Jul 10 17:32:38 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||||
|
|
||||||
* sample/test.rb: update test suites.
|
* sample/test.rb: update test suites.
|
||||||
|
|
|
@ -33,6 +33,64 @@ class << TclTkIp
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
################################################
|
||||||
|
# use pseudo-toplevel feature of MultiTkIp ?
|
||||||
|
if (!defined?(Use_PseudoToplevel_Feature_of_MultiTkIp) ||
|
||||||
|
Use_PseudoToplevel_Feature_of_MultiTkIp)
|
||||||
|
module MultiTkIp_PseudoToplevel_Evaluable
|
||||||
|
#def pseudo_toplevel_eval(body = Proc.new)
|
||||||
|
# Thread.current[:TOPLEVEL] = self
|
||||||
|
# begin
|
||||||
|
# body.call
|
||||||
|
# ensure
|
||||||
|
# Thread.current[:TOPLEVEL] = nil
|
||||||
|
# end
|
||||||
|
#end
|
||||||
|
|
||||||
|
def pseudo_toplevel_evaluable?
|
||||||
|
@pseudo_toplevel_evaluable
|
||||||
|
end
|
||||||
|
|
||||||
|
def pseudo_toplevel_evaluable=(mode)
|
||||||
|
@pseudo_toplevel_evaluable = (mode)? true: false
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.extended(mod)
|
||||||
|
mod.__send__(:extend_object, mod)
|
||||||
|
mod.instance_variable_set('@pseudo_toplevel_evaluable', true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Object
|
||||||
|
alias __method_missing_alias_for_MultiTkIp__ method_missing
|
||||||
|
private :__method_missing_alias_for_MultiTkIp__
|
||||||
|
|
||||||
|
def method_missing(id, *args)
|
||||||
|
begin
|
||||||
|
has_top = (top = MultiTkIp.__getip.__pseudo_toplevel) &&
|
||||||
|
top.respond_to?(:pseudo_toplevel_evaluable?) &&
|
||||||
|
top.pseudo_toplevel_evaluable? &&
|
||||||
|
top.respond_to?(id)
|
||||||
|
rescue Exception => e
|
||||||
|
has_top = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if has_top
|
||||||
|
top.__send__(id, *args)
|
||||||
|
else
|
||||||
|
__method_missing_alias_for_MultiTkIp__(id, *args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# dummy
|
||||||
|
module MultiTkIp_PseudoToplevel_Evaluable
|
||||||
|
def pseudo_toplevel_evaluable?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
################################################
|
################################################
|
||||||
# exceptiopn to treat the return value from IP
|
# exceptiopn to treat the return value from IP
|
||||||
class MultiTkIp_OK < Exception
|
class MultiTkIp_OK < Exception
|
||||||
|
@ -54,6 +112,8 @@ MultiTkIp_OK.freeze
|
||||||
################################################
|
################################################
|
||||||
# methods for construction
|
# methods for construction
|
||||||
class MultiTkIp
|
class MultiTkIp
|
||||||
|
BASE_DIR = File.dirname(__FILE__)
|
||||||
|
|
||||||
@@SLAVE_IP_ID = ['slave'.freeze, '0'.taint].freeze
|
@@SLAVE_IP_ID = ['slave'.freeze, '0'.taint].freeze
|
||||||
|
|
||||||
@@IP_TABLE = {}.taint unless defined?(@@IP_TABLE)
|
@@IP_TABLE = {}.taint unless defined?(@@IP_TABLE)
|
||||||
|
@ -692,6 +752,46 @@ class MultiTkIp
|
||||||
|
|
||||||
#################################
|
#################################
|
||||||
|
|
||||||
|
@pseudo_toplevel = [false, nil]
|
||||||
|
|
||||||
|
def self.__pseudo_toplevel
|
||||||
|
self.__pseudo_toplevel_evaluable? && @pseudo_toplevel[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.__pseudo_toplevel=(m)
|
||||||
|
unless (Thread.current.group == ThreadGroup::Default &&
|
||||||
|
MultiTkIp.__getip == @@DEFAULT_MASTER)
|
||||||
|
fail SecurityError, "no permission to manipulate"
|
||||||
|
end
|
||||||
|
|
||||||
|
if m.kind_of?(Module) && m.respond_to?(:pseudo_toplevel_evaluable?)
|
||||||
|
@pseudo_toplevel[0] = true
|
||||||
|
@pseudo_toplevel[1] = m
|
||||||
|
else
|
||||||
|
fail ArgumentError, 'fail to set pseudo-toplevel'
|
||||||
|
end
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.__pseudo_toplevel_evaluable?
|
||||||
|
begin
|
||||||
|
@pseudo_toplevel[0] && @pseudo_toplevel[1].pseudo_toplevel_evaluable?
|
||||||
|
rescue Exception
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.__pseudo_toplevel_evaluable=(mode)
|
||||||
|
unless (Thread.current.group == ThreadGroup::Default &&
|
||||||
|
MultiTkIp.__getip == @@DEFAULT_MASTER)
|
||||||
|
fail SecurityError, "no permission to manipulate"
|
||||||
|
end
|
||||||
|
|
||||||
|
@pseudo_toplevel[0] = (mode)? true: false
|
||||||
|
end
|
||||||
|
|
||||||
|
#################################
|
||||||
|
|
||||||
@assign_request = Class.new(Exception){
|
@assign_request = Class.new(Exception){
|
||||||
def self.new(target, ret)
|
def self.new(target, ret)
|
||||||
obj = super()
|
obj = super()
|
||||||
|
@ -746,10 +846,40 @@ class MultiTkIp
|
||||||
|
|
||||||
#################################
|
#################################
|
||||||
|
|
||||||
|
@init_ip_env_queue = Queue.new
|
||||||
|
Thread.new{
|
||||||
|
current = Thread.current
|
||||||
|
loop {
|
||||||
|
mtx, ret, table, script = @init_ip_env_queue.deq
|
||||||
|
begin
|
||||||
|
ret[0] = table.each{|tg, ip| ip._init_ip_env(script) }
|
||||||
|
rescue Exception => e
|
||||||
|
ret[0] = e
|
||||||
|
ensure
|
||||||
|
mtx.unlock
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def self.__init_ip_env__(table, script)
|
||||||
|
ret = []
|
||||||
|
mtx = Mutex.new.lock
|
||||||
|
@init_ip_env_queue.enq([mtx, ret, table, script])
|
||||||
|
mtx.lock
|
||||||
|
if ret[0].kind_of?(Exception)
|
||||||
|
raise ret[0]
|
||||||
|
else
|
||||||
|
ret[0]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#################################
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
undef :instance_eval
|
undef :instance_eval
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
@@DEFAULT_MASTER.freeze # defend against modification
|
@@DEFAULT_MASTER.freeze # defend against modification
|
||||||
|
|
||||||
######################################
|
######################################
|
||||||
|
@ -1115,6 +1245,8 @@ class MultiTkIp
|
||||||
|
|
||||||
@threadgroup = ThreadGroup.new
|
@threadgroup = ThreadGroup.new
|
||||||
|
|
||||||
|
@pseudo_toplevel = [false, nil]
|
||||||
|
|
||||||
@cmd_queue = Queue.new
|
@cmd_queue = Queue.new
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
@ -1424,6 +1556,17 @@ class MultiTkIp
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def _remove_tk_procs(*names)
|
||||||
|
return if slave?
|
||||||
|
names.each{|name|
|
||||||
|
name = name.to_s
|
||||||
|
@interp._invoke('rename', name, '')
|
||||||
|
@interp._invoke('interp', 'slaves').split.each{|slave|
|
||||||
|
@interp._invoke('interp', 'alias', slave, name, '') rescue nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def _init_ip_internal(init_ip_env, add_tk_procs)
|
def _init_ip_internal(init_ip_env, add_tk_procs)
|
||||||
#init_ip_env.each{|script| self.eval_proc{script.call(self)}}
|
#init_ip_env.each{|script| self.eval_proc{script.call(self)}}
|
||||||
init_ip_env.each{|script| self._init_ip_env(script)}
|
init_ip_env.each{|script| self._init_ip_env(script)}
|
||||||
|
@ -1450,9 +1593,21 @@ class MultiTkIp
|
||||||
__getip._tk_table_list[id]
|
__getip._tk_table_list[id]
|
||||||
end
|
end
|
||||||
def self.create_table
|
def self.create_table
|
||||||
#if __getip.slave?
|
if __getip.slave?
|
||||||
# raise SecurityError, "slave-IP has no permission creating a new table"
|
begin
|
||||||
#end
|
raise SecurityError, "slave-IP has no permission creating a new table"
|
||||||
|
rescue SecurityError => e
|
||||||
|
#p e.backtrace
|
||||||
|
# Is called on a Ruby/Tk library?
|
||||||
|
caller_info = e.backtrace[1]
|
||||||
|
if caller_info =~ %r{^#{MultiTkIp::BASE_DIR}/(tk|tkextlib)/[^:]+\.rb:}
|
||||||
|
# Probably, caller is a Ruby/Tk library --> allow creating
|
||||||
|
else
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
id = @@TK_TABLE_LIST.size
|
id = @@TK_TABLE_LIST.size
|
||||||
obj = Object.new
|
obj = Object.new
|
||||||
@@TK_TABLE_LIST << obj
|
@@TK_TABLE_LIST << obj
|
||||||
|
@ -1468,15 +1623,48 @@ class MultiTkIp
|
||||||
|
|
||||||
def self.init_ip_env(script = Proc.new)
|
def self.init_ip_env(script = Proc.new)
|
||||||
@@INIT_IP_ENV << script
|
@@INIT_IP_ENV << script
|
||||||
@@IP_TABLE.each{|tg, ip|
|
if __getip.slave?
|
||||||
ip._init_ip_env(script)
|
begin
|
||||||
}
|
raise SecurityError, "slave-IP has no permission initializing IP env"
|
||||||
|
rescue SecurityError => e
|
||||||
|
#p e.backtrace
|
||||||
|
# Is called on a Ruby/Tk library?
|
||||||
|
caller_info = e.backtrace[1]
|
||||||
|
if caller_info =~ %r{^#{MultiTkIp::BASE_DIR}/(tk|tkextlib)/[^:]+\.rb:}
|
||||||
|
# Probably, caller is a Ruby/Tk library --> allow creating
|
||||||
|
else
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# @@IP_TABLE.each{|tg, ip|
|
||||||
|
# ip._init_ip_env(script)
|
||||||
|
# }
|
||||||
|
@@DEFAULT_MASTER.__init_ip_env__(@@IP_TABLE, script)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.add_tk_procs(name, args=nil, body=nil)
|
def self.add_tk_procs(name, args=nil, body=nil)
|
||||||
@@ADD_TK_PROCS << [name, args, body]
|
if name.kind_of?(Array) # => an array of [name, args, body]
|
||||||
|
name.each{|param| self.add_tk_procs(*param)}
|
||||||
|
else
|
||||||
|
name = name.to_s
|
||||||
|
@@ADD_TK_PROCS << [name, args, body]
|
||||||
|
@@IP_TABLE.each{|tg, ip|
|
||||||
|
ip._add_tk_procs(name, args, body)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.remove_tk_procs(*names)
|
||||||
|
names.each{|name|
|
||||||
|
name = name.to_s
|
||||||
|
@@ADD_TK_PROCS.delete_if{|elem|
|
||||||
|
elem.kind_of?(Array) && elem[0].to_s == name
|
||||||
|
}
|
||||||
|
}
|
||||||
@@IP_TABLE.each{|tg, ip|
|
@@IP_TABLE.each{|tg, ip|
|
||||||
ip._add_tk_procs(name, args, body)
|
ip._remove_tk_procs(*names)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1565,6 +1753,46 @@ class MultiTkIp
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# pseudo-toplevel operation support
|
||||||
|
class MultiTkIp
|
||||||
|
# instance method
|
||||||
|
def __pseudo_toplevel
|
||||||
|
self.__pseudo_toplevel_evaluable? && @pseudo_toplevel[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
def __pseudo_toplevel=(m)
|
||||||
|
unless (Thread.current.group == ThreadGroup::Default &&
|
||||||
|
MultiTkIp.__getip == @@DEFAULT_MASTER)
|
||||||
|
fail SecurityError, "no permission to manipulate"
|
||||||
|
end
|
||||||
|
|
||||||
|
if m.kind_of?(Module) && m.respond_to?(:pseudo_toplevel_evaluable?)
|
||||||
|
@pseudo_toplevel[0] = true
|
||||||
|
@pseudo_toplevel[1] = m
|
||||||
|
else
|
||||||
|
fail ArgumentError, 'fail to set pseudo-toplevel'
|
||||||
|
end
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def __pseudo_toplevel_evaluable?
|
||||||
|
begin
|
||||||
|
@pseudo_toplevel[0] && @pseudo_toplevel[1].pseudo_toplevel_evaluable?
|
||||||
|
rescue Exception
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def __pseudo_toplevel_evaluable=(mode)
|
||||||
|
unless (Thread.current.group == ThreadGroup::Default &&
|
||||||
|
MultiTkIp.__getip == @@DEFAULT_MASTER)
|
||||||
|
fail SecurityError, "no permission to manipulate"
|
||||||
|
end
|
||||||
|
|
||||||
|
@pseudo_toplevel[0] = (mode)? true: false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# evaluate a procedure on the proper interpreter
|
# evaluate a procedure on the proper interpreter
|
||||||
class MultiTkIp
|
class MultiTkIp
|
||||||
# instance method
|
# instance method
|
||||||
|
|
|
@ -1192,8 +1192,22 @@ module TkCore
|
||||||
script.call(self)
|
script.call(self)
|
||||||
end
|
end
|
||||||
def INTERP.add_tk_procs(name, args = nil, body = nil)
|
def INTERP.add_tk_procs(name, args = nil, body = nil)
|
||||||
@add_tk_procs << [name, args, body]
|
if name.kind_of?(Array)
|
||||||
self._invoke('proc', name, args, body) if args && body
|
name.each{|param| self.add_tk_procs(*param)}
|
||||||
|
else
|
||||||
|
name = name.to_s
|
||||||
|
@add_tk_procs << [name, args, body]
|
||||||
|
self._invoke('proc', name, args, body) if args && body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
def INTERP.remove_tk_procs(*names)
|
||||||
|
names.each{|name|
|
||||||
|
name = name.to_s
|
||||||
|
@add_tk_procs.delete_if{|elem|
|
||||||
|
elem.kind_of?(Array) && elem[0].to_s == name
|
||||||
|
}
|
||||||
|
self._invoke('rename', name, '')
|
||||||
|
}
|
||||||
end
|
end
|
||||||
def INTERP.init_ip_internal
|
def INTERP.init_ip_internal
|
||||||
ip = self
|
ip = self
|
||||||
|
@ -1285,6 +1299,8 @@ module TkCore
|
||||||
EOL
|
EOL
|
||||||
=end
|
=end
|
||||||
|
|
||||||
|
at_exit{ INTERP.remove_tk_procs(TclTkLib::FINALIZE_PROC_NAME) }
|
||||||
|
|
||||||
EventFlag = TclTkLib::EventFlag
|
EventFlag = TclTkLib::EventFlag
|
||||||
|
|
||||||
def callback_break
|
def callback_break
|
||||||
|
@ -3886,12 +3902,14 @@ class TkObject<TkKernel
|
||||||
begin
|
begin
|
||||||
cget(name)
|
cget(name)
|
||||||
rescue
|
rescue
|
||||||
fail NameError,
|
super(id, *args)
|
||||||
"undefined local variable or method `#{name}' for #{self.to_s}",
|
# fail NameError,
|
||||||
error_at
|
# "undefined local variable or method `#{name}' for #{self.to_s}",
|
||||||
|
# error_at
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at
|
super(id, *args)
|
||||||
|
# fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -4563,7 +4581,7 @@ end
|
||||||
#Tk.freeze
|
#Tk.freeze
|
||||||
|
|
||||||
module Tk
|
module Tk
|
||||||
RELEASE_DATE = '2006-07-03'.freeze
|
RELEASE_DATE = '2006-07-10'.freeze
|
||||||
|
|
||||||
autoload :AUTO_PATH, 'tk/variable'
|
autoload :AUTO_PATH, 'tk/variable'
|
||||||
autoload :TCL_PACKAGE_PATH, 'tk/variable'
|
autoload :TCL_PACKAGE_PATH, 'tk/variable'
|
||||||
|
|
|
@ -859,10 +859,12 @@ class TkFont
|
||||||
begin
|
begin
|
||||||
configinfo name
|
configinfo name
|
||||||
rescue
|
rescue
|
||||||
fail NameError, "undefined local variable or method `#{name}' for #{self.to_s}", error_at
|
super(id, *args)
|
||||||
end
|
# fail NameError, "undefined local variable or method `#{name}' for #{self.to_s}", error_at
|
||||||
|
# end
|
||||||
else
|
else
|
||||||
fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at
|
super(id, *args)
|
||||||
|
# fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,8 @@ class TkMsgCatalog < TkObject
|
||||||
self.set_translation(loc, *args)
|
self.set_translation(loc, *args)
|
||||||
|
|
||||||
else
|
else
|
||||||
fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at
|
super(id, *args)
|
||||||
|
# fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -289,7 +289,8 @@ module Tk
|
||||||
end
|
end
|
||||||
|
|
||||||
# unknown method
|
# unknown method
|
||||||
fail RuntimeError, "unknown method '#{name}' for #{self.inspect}"
|
super(id, *args)
|
||||||
|
# fail RuntimeError, "unknown method '#{name}' for #{self.inspect}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def tk_send(cmd, *rest)
|
def tk_send(cmd, *rest)
|
||||||
|
|
|
@ -509,12 +509,93 @@ else # ver >= 8.4
|
||||||
alias showVars showVars2
|
alias showVars showVars2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Pseudo-Toplevel support
|
||||||
|
module PseudoToplevel_Evaluable
|
||||||
|
def pseudo_toplevel_eval(body = Proc.new)
|
||||||
|
Thread.current[:TOPLEVEL] = self
|
||||||
|
begin
|
||||||
|
body.call
|
||||||
|
ensure
|
||||||
|
Thread.current[:TOPLEVEL] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pseudo_toplevel_evaluable?
|
||||||
|
@pseudo_toplevel_evaluable
|
||||||
|
end
|
||||||
|
def pseudo_toplevel_evaluable=(mode)
|
||||||
|
@pseudo_toplevel_evaluable = (mode)? true: false
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.extended(mod)
|
||||||
|
mod.__send__(:extend_object, mod)
|
||||||
|
mod.instance_variable_set('@pseudo_toplevel_evaluable', true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Object
|
||||||
|
alias __method_missing__ method_missing
|
||||||
|
private :__method_missing__
|
||||||
|
|
||||||
|
def method_missing(id, *args)
|
||||||
|
begin
|
||||||
|
has_top = (top = Thread.current[:TOPLEVEL]) &&
|
||||||
|
top.respond_to?(:pseudo_toplevel_evaluable?) &&
|
||||||
|
top.pseudo_toplevel_evaluable? &&
|
||||||
|
top.respond_to?(id)
|
||||||
|
rescue Exception => e
|
||||||
|
has_top = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if has_top
|
||||||
|
top.__send__(id, *args)
|
||||||
|
else
|
||||||
|
__method_missing__(id, *args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Proc
|
||||||
|
def initialize(*args, &b)
|
||||||
|
super
|
||||||
|
@__pseudo_toplevel__ = Thread.current[:TOPLEVEL]
|
||||||
|
end
|
||||||
|
|
||||||
|
alias __call__ call
|
||||||
|
def call(*args, &b)
|
||||||
|
if top = @__pseudo_toplevel__
|
||||||
|
orig_top = Thread.current[:TOPLEVEL]
|
||||||
|
Thread.current[:TOPLEVEL] = top
|
||||||
|
begin
|
||||||
|
__call__(*args, &b)
|
||||||
|
ensure
|
||||||
|
Thread.current[:TOPLEVEL] = orig_top
|
||||||
|
end
|
||||||
|
else
|
||||||
|
__call__(*args, &b)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def proc(&b)
|
||||||
|
Proc.new(&b)
|
||||||
|
end
|
||||||
|
def lambda(&b)
|
||||||
|
Proc.new(&b)
|
||||||
|
end
|
||||||
|
|
||||||
def _null_binding
|
def _null_binding
|
||||||
|
Module.new.instance_eval{extend PseudoToplevel_Evaluable}
|
||||||
# binding
|
# binding
|
||||||
Module.new.instance_eval{binding}
|
# Module.new.instance_eval{binding}
|
||||||
end
|
end
|
||||||
private :_null_binding
|
private :_null_binding
|
||||||
|
|
||||||
|
def eval_samplecode(code)
|
||||||
|
Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } }.run
|
||||||
|
Tk.update
|
||||||
|
end
|
||||||
|
|
||||||
# invoke --
|
# invoke --
|
||||||
# This procedure is called when the user clicks on a demo description.
|
# This procedure is called when the user clicks on a demo description.
|
||||||
# It is responsible for invoking the demonstration.
|
# It is responsible for invoking the demonstration.
|
||||||
|
@ -529,8 +610,9 @@ def invoke(txt, idx)
|
||||||
cursor = txt.cget('cursor')
|
cursor = txt.cget('cursor')
|
||||||
txt.cursor('watch')
|
txt.cursor('watch')
|
||||||
Tk.update
|
Tk.update
|
||||||
eval(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, _null_binding)
|
# eval(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, _null_binding)
|
||||||
Tk.update
|
# Tk.update
|
||||||
|
eval_samplecode(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join)
|
||||||
txt.cursor(cursor)
|
txt.cursor(cursor)
|
||||||
|
|
||||||
$tag_visited.add("#{idx} linestart +1 chars", "#{idx} lineend +1 chars")
|
$tag_visited.add("#{idx} linestart +1 chars", "#{idx} lineend +1 chars")
|
||||||
|
@ -596,7 +678,8 @@ def showCode1(demo)
|
||||||
}.pack('side'=>'left', 'expand'=>'yes', 'pady'=>2)
|
}.pack('side'=>'left', 'expand'=>'yes', 'pady'=>2)
|
||||||
TkButton.new(f) {
|
TkButton.new(f) {
|
||||||
text "Rerun Demo"
|
text "Rerun Demo"
|
||||||
command proc{eval($code_text.get('1.0','end'), _null_binding)}
|
# command proc{eval($code_text.get('1.0','end'), _null_binding)}
|
||||||
|
command proc{eval_samplecode($code_text.get('1.0','end'))}
|
||||||
}.pack('side'=>'left', 'expand'=>'yes', 'pady'=>2)
|
}.pack('side'=>'left', 'expand'=>'yes', 'pady'=>2)
|
||||||
# f.pack('side'=>'bottom', 'expand'=>'yes', 'fill'=>'x')
|
# f.pack('side'=>'bottom', 'expand'=>'yes', 'fill'=>'x')
|
||||||
f.pack('side'=>'bottom', 'fill'=>'x')
|
f.pack('side'=>'bottom', 'fill'=>'x')
|
||||||
|
@ -690,7 +773,8 @@ def showCode2(demo)
|
||||||
:image=>$image['print'], :compound=>:left)
|
:image=>$image['print'], :compound=>:left)
|
||||||
b_run = TkButton.new(bf, :text=>'Rerun Demo',
|
b_run = TkButton.new(bf, :text=>'Rerun Demo',
|
||||||
:command=>proc{
|
:command=>proc{
|
||||||
eval($code_text.get('1.0','end'), _null_binding)
|
# eval($code_text.get('1.0','end'), _null_binding)
|
||||||
|
eval_samplecode($code_text.get('1.0','end'))
|
||||||
},
|
},
|
||||||
:image=>$image['refresh'], :compound=>:left)
|
:image=>$image['refresh'], :compound=>:left)
|
||||||
|
|
||||||
|
@ -812,7 +896,7 @@ end
|
||||||
#
|
#
|
||||||
def aboutBox
|
def aboutBox
|
||||||
Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo',
|
Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo',
|
||||||
'message'=>"Ruby/Tk widget demonstration Ver.1.5.6-en\n\n" +
|
'message'=>"Ruby/Tk widget demonstration Ver.1.6.0-en\n\n" +
|
||||||
"based on demos of Tk8.1 -- 8.5 " +
|
"based on demos of Tk8.1 -- 8.5 " +
|
||||||
"( Copyright:: " +
|
"( Copyright:: " +
|
||||||
"(c) 1996-1997 Sun Microsystems, Inc. / " +
|
"(c) 1996-1997 Sun Microsystems, Inc. / " +
|
||||||
|
@ -837,11 +921,12 @@ ARGV.each{|cmd|
|
||||||
if cmd =~ /(.*).rb/
|
if cmd =~ /(.*).rb/
|
||||||
cmd = $1
|
cmd = $1
|
||||||
end
|
end
|
||||||
eval(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join,
|
#eval(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join,
|
||||||
_null_binding)
|
# _null_binding)
|
||||||
|
eval_samplecode(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join)
|
||||||
}
|
}
|
||||||
if no_launcher
|
if no_launcher
|
||||||
$root.withdraw # hide root window
|
$root.withdraw # hide root window
|
||||||
Thread.start{
|
Thread.start{
|
||||||
loop do
|
loop do
|
||||||
count = 0
|
count = 0
|
||||||
|
|
|
@ -551,12 +551,93 @@ else # ver >= 8.4
|
||||||
alias showVars showVars2
|
alias showVars showVars2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# 疑似トップレベルサポート
|
||||||
|
module PseudoToplevel_Evaluable
|
||||||
|
def pseudo_toplevel_eval(body = Proc.new)
|
||||||
|
Thread.current[:TOPLEVEL] = self
|
||||||
|
begin
|
||||||
|
body.call
|
||||||
|
ensure
|
||||||
|
Thread.current[:TOPLEVEL] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pseudo_toplevel_evaluable?
|
||||||
|
@pseudo_toplevel_evaluable
|
||||||
|
end
|
||||||
|
def pseudo_toplevel_evaluable=(mode)
|
||||||
|
@pseudo_toplevel_evaluable = (mode)? true: false
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.extended(mod)
|
||||||
|
mod.__send__(:extend_object, mod)
|
||||||
|
mod.instance_variable_set('@pseudo_toplevel_evaluable', true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Object
|
||||||
|
alias __method_missing__ method_missing
|
||||||
|
private :__method_missing__
|
||||||
|
|
||||||
|
def method_missing(id, *args)
|
||||||
|
begin
|
||||||
|
has_top = (top = Thread.current[:TOPLEVEL]) &&
|
||||||
|
top.respond_to?(:pseudo_toplevel_evaluable?) &&
|
||||||
|
top.pseudo_toplevel_evaluable? &&
|
||||||
|
top.respond_to?(id)
|
||||||
|
rescue Exception => e
|
||||||
|
has_top = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if has_top
|
||||||
|
top.__send__(id, *args)
|
||||||
|
else
|
||||||
|
__method_missing__(id, *args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Proc
|
||||||
|
def initialize(*args, &b)
|
||||||
|
super
|
||||||
|
@__pseudo_toplevel__ = Thread.current[:TOPLEVEL]
|
||||||
|
end
|
||||||
|
|
||||||
|
alias __call__ call
|
||||||
|
def call(*args, &b)
|
||||||
|
if top = @__pseudo_toplevel__
|
||||||
|
orig_top = Thread.current[:TOPLEVEL]
|
||||||
|
Thread.current[:TOPLEVEL] = top
|
||||||
|
begin
|
||||||
|
__call__(*args, &b)
|
||||||
|
ensure
|
||||||
|
Thread.current[:TOPLEVEL] = orig_top
|
||||||
|
end
|
||||||
|
else
|
||||||
|
__call__(*args, &b)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def proc(&b)
|
||||||
|
Proc.new(&b)
|
||||||
|
end
|
||||||
|
def lambda(&b)
|
||||||
|
Proc.new(&b)
|
||||||
|
end
|
||||||
|
|
||||||
def _null_binding
|
def _null_binding
|
||||||
|
Module.new.instance_eval{extend PseudoToplevel_Evaluable}
|
||||||
# binding
|
# binding
|
||||||
Module.new.instance_eval{binding}
|
# Module.new.instance_eval{binding}
|
||||||
end
|
end
|
||||||
private :_null_binding
|
private :_null_binding
|
||||||
|
|
||||||
|
def eval_samplecode(code)
|
||||||
|
Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } }.run
|
||||||
|
Tk.update
|
||||||
|
end
|
||||||
|
|
||||||
# テキスト上での click に対する動作
|
# テキスト上での click に対する動作
|
||||||
def invoke(txt, idx)
|
def invoke(txt, idx)
|
||||||
tag = txt.tag_names(idx).find{|t| t.kind_of?(String) && t =~ /^demo-/}
|
tag = txt.tag_names(idx).find{|t| t.kind_of?(String) && t =~ /^demo-/}
|
||||||
|
@ -565,8 +646,9 @@ def invoke(txt, idx)
|
||||||
cursor = txt.cget('cursor')
|
cursor = txt.cget('cursor')
|
||||||
txt.cursor('watch')
|
txt.cursor('watch')
|
||||||
Tk.update
|
Tk.update
|
||||||
eval(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, _null_binding)
|
# eval(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, _null_binding)
|
||||||
Tk.update
|
# Tk.update
|
||||||
|
eval_samplecode(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join)
|
||||||
txt.cursor(cursor)
|
txt.cursor(cursor)
|
||||||
|
|
||||||
$tag_visited.add("#{idx} linestart +1 chars", "#{idx} lineend +1 chars")
|
$tag_visited.add("#{idx} linestart +1 chars", "#{idx} lineend +1 chars")
|
||||||
|
@ -622,7 +704,8 @@ def showCode1(demo)
|
||||||
}.pack('side'=>'left', 'expand'=>'yes', 'pady'=>2)
|
}.pack('side'=>'left', 'expand'=>'yes', 'pady'=>2)
|
||||||
TkButton.new(f) {
|
TkButton.new(f) {
|
||||||
text "再実行"
|
text "再実行"
|
||||||
command proc{eval($code_text.get('1.0','end'), _null_binding)}
|
# command proc{eval($code_text.get('1.0','end'), _null_binding)}
|
||||||
|
command proc{eval_samplecode($code_text.get('1.0','end'))}
|
||||||
}.pack('side'=>'left', 'expand'=>'yes', 'pady'=>2)
|
}.pack('side'=>'left', 'expand'=>'yes', 'pady'=>2)
|
||||||
# f.pack('side'=>'bottom', 'expand'=>'yes', 'fill'=>'x')
|
# f.pack('side'=>'bottom', 'expand'=>'yes', 'fill'=>'x')
|
||||||
f.pack('side'=>'bottom', 'fill'=>'x')
|
f.pack('side'=>'bottom', 'fill'=>'x')
|
||||||
|
@ -716,7 +799,8 @@ def showCode2(demo)
|
||||||
:image=>$image['print'], :compound=>:left)
|
:image=>$image['print'], :compound=>:left)
|
||||||
b_run = TkButton.new(bf, :text=>'再実行',
|
b_run = TkButton.new(bf, :text=>'再実行',
|
||||||
:command=>proc{
|
:command=>proc{
|
||||||
eval($code_text.get('1.0','end'), _null_binding)
|
# eval($code_text.get('1.0','end'), _null_binding)
|
||||||
|
eval_samplecode($code_text.get('1.0','end'))
|
||||||
},
|
},
|
||||||
:image=>$image['refresh'], :compound=>:left)
|
:image=>$image['refresh'], :compound=>:left)
|
||||||
|
|
||||||
|
@ -842,7 +926,7 @@ end
|
||||||
#
|
#
|
||||||
def aboutBox
|
def aboutBox
|
||||||
Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo',
|
Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo',
|
||||||
'message'=>"Ruby/Tk ウィジェットデモ Ver.1.5.6-jp\n\n" +
|
'message'=>"Ruby/Tk ウィジェットデモ Ver.1.6.0-jp\n\n" +
|
||||||
"based on demos of Tk8.1 -- 8.5 " +
|
"based on demos of Tk8.1 -- 8.5 " +
|
||||||
"( Copyright:: " +
|
"( Copyright:: " +
|
||||||
"(c) 1996-1997 Sun Microsystems, Inc. / " +
|
"(c) 1996-1997 Sun Microsystems, Inc. / " +
|
||||||
|
@ -867,8 +951,9 @@ ARGV.each{|cmd|
|
||||||
if cmd =~ /(.*).rb/
|
if cmd =~ /(.*).rb/
|
||||||
cmd = $1
|
cmd = $1
|
||||||
end
|
end
|
||||||
eval(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join,
|
#eval(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join,
|
||||||
_null_binding)
|
# _null_binding)
|
||||||
|
eval_samplecode(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join)
|
||||||
}
|
}
|
||||||
if no_launcher
|
if no_launcher
|
||||||
$root.withdraw # hide root window
|
$root.withdraw # hide root window
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* Oct. 24, 1997 Y. Matsumoto
|
* Oct. 24, 1997 Y. Matsumoto
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define TCLTKLIB_RELEASE_DATE "2006-07-03"
|
#define TCLTKLIB_RELEASE_DATE "2006-07-10"
|
||||||
|
|
||||||
#include "ruby.h"
|
#include "ruby.h"
|
||||||
#include "rubysig.h"
|
#include "rubysig.h"
|
||||||
|
@ -81,6 +81,8 @@ static char *finalize_hook_name = "INTERP_FINALIZE_HOOK";
|
||||||
|
|
||||||
static void ip_finalize _((Tcl_Interp*));
|
static void ip_finalize _((Tcl_Interp*));
|
||||||
|
|
||||||
|
static int at_exit = 0;
|
||||||
|
|
||||||
|
|
||||||
/* for callback break & continue */
|
/* for callback break & continue */
|
||||||
static VALUE eTkCallbackReturn;
|
static VALUE eTkCallbackReturn;
|
||||||
|
@ -4358,6 +4360,33 @@ delete_slaves(ip)
|
||||||
|
|
||||||
|
|
||||||
/* finalize operation */
|
/* finalize operation */
|
||||||
|
static VALUE
|
||||||
|
lib_mark_at_exit(self)
|
||||||
|
VALUE self;
|
||||||
|
{
|
||||||
|
at_exit = 1;
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
#if TCL_MAJOR_VERSION >= 8
|
||||||
|
ip_null_proc(clientData, interp, argc, argv)
|
||||||
|
ClientData clientData;
|
||||||
|
Tcl_Interp *interp;
|
||||||
|
int argc;
|
||||||
|
Tcl_Obj *CONST argv[];
|
||||||
|
#else /* TCL_MAJOR_VERSION < 8 */
|
||||||
|
ip_null_proc(clientData, interp, argc, argv)
|
||||||
|
ClientData clientData;
|
||||||
|
Tcl_Interp *interp;
|
||||||
|
int argc;
|
||||||
|
char *argv[];
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Tcl_ResetResult(interp);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ip_finalize(ip)
|
ip_finalize(ip)
|
||||||
Tcl_Interp *ip;
|
Tcl_Interp *ip;
|
||||||
|
@ -4403,6 +4432,29 @@ ip_finalize(ip)
|
||||||
/* delete slaves */
|
/* delete slaves */
|
||||||
delete_slaves(ip);
|
delete_slaves(ip);
|
||||||
|
|
||||||
|
/* shut off some connections from Tcl-proc to Ruby */
|
||||||
|
if (at_exit) {
|
||||||
|
/* NOTE: Only when at exit.
|
||||||
|
Because, ruby removes objects, which depends on the deleted
|
||||||
|
interpreter, on some callback operations.
|
||||||
|
It is important for GC. */
|
||||||
|
#if TCL_MAJOR_VERSION >= 8
|
||||||
|
Tcl_CreateObjCommand(ip, "ruby", ip_null_proc,
|
||||||
|
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
|
||||||
|
Tcl_CreateObjCommand(ip, "ruby_eval", ip_null_proc,
|
||||||
|
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
|
||||||
|
Tcl_CreateObjCommand(ip, "ruby_cmd", ip_null_proc,
|
||||||
|
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
|
||||||
|
#else /* TCL_MAJOR_VERSION < 8 */
|
||||||
|
Tcl_CreateCommand(ip, "ruby", ip_null_proc,
|
||||||
|
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
|
||||||
|
Tcl_CreateCommand(ip, "ruby_eval", ip_null_proc,
|
||||||
|
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
|
||||||
|
Tcl_CreateCommand(ip, "ruby_cmd", ip_null_proc,
|
||||||
|
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* delete root widget */
|
/* delete root widget */
|
||||||
#if 0
|
#if 0
|
||||||
DUMP1("check `destroy'");
|
DUMP1("check `destroy'");
|
||||||
|
@ -4425,7 +4477,7 @@ ip_finalize(ip)
|
||||||
|
|
||||||
/* call finalize-hook-proc */
|
/* call finalize-hook-proc */
|
||||||
DUMP1("check `finalize-hook-proc'");
|
DUMP1("check `finalize-hook-proc'");
|
||||||
if (Tcl_GetCommandInfo(ip, finalize_hook_name, &info)) {
|
if ( Tcl_GetCommandInfo(ip, finalize_hook_name, &info)) {
|
||||||
DUMP2("call finalize hook proc '%s'", finalize_hook_name);
|
DUMP2("call finalize hook proc '%s'", finalize_hook_name);
|
||||||
ruby_debug = Qfalse;
|
ruby_debug = Qfalse;
|
||||||
ruby_verbose = Qnil;
|
ruby_verbose = Qnil;
|
||||||
|
@ -4680,7 +4732,6 @@ ip_CallWhenDeleted(clientData, ip)
|
||||||
rb_thread_critical = thr_crit_bup;
|
rb_thread_critical = thr_crit_bup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* initialize interpreter */
|
/* initialize interpreter */
|
||||||
static VALUE
|
static VALUE
|
||||||
ip_init(argc, argv, self)
|
ip_init(argc, argv, self)
|
||||||
|
@ -7925,6 +7976,8 @@ Init_tcltklib()
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
|
|
||||||
|
rb_define_module_function(lib, "_mark_at_exit", lib_mark_at_exit, 0);
|
||||||
|
|
||||||
rb_define_module_function(lib, "mainloop", lib_mainloop, -1);
|
rb_define_module_function(lib, "mainloop", lib_mainloop, -1);
|
||||||
rb_define_module_function(lib, "mainloop_thread?",
|
rb_define_module_function(lib, "mainloop_thread?",
|
||||||
lib_evloop_thread_p, 0);
|
lib_evloop_thread_p, 0);
|
||||||
|
@ -8061,6 +8114,10 @@ Init_tcltklib()
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
|
|
||||||
|
rb_eval_string("at_exit{ TclTkLib._mark_at_exit }");
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------- */
|
||||||
|
|
||||||
ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0);
|
ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0);
|
||||||
switch(ret) {
|
switch(ret) {
|
||||||
case TCLTK_STUBS_OK:
|
case TCLTK_STUBS_OK:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue