summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog26
-rw-r--r--ext/tk/lib/multi-tk.rb244
-rw-r--r--ext/tk/lib/tk.rb32
-rw-r--r--ext/tk/lib/tk/font.rb8
-rw-r--r--ext/tk/lib/tk/msgcat.rb3
-rw-r--r--ext/tk/lib/tkextlib/itk/incr_tk.rb3
-rw-r--r--ext/tk/sample/demos-en/widget103
-rw-r--r--ext/tk/sample/demos-jp/widget101
-rw-r--r--ext/tk/tcltklib.c63
9 files changed, 543 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index ebf78f0bac..e68adb167f 100644
--- a/ChangeLog
+++ b/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 13:58:40 2006 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* signal.c (ruby_nativethread_signal, posix_nativethread_signal,
diff --git a/ext/tk/lib/multi-tk.rb b/ext/tk/lib/multi-tk.rb
index 42f92c3b55..645e5ca2ea 100644
--- a/ext/tk/lib/multi-tk.rb
+++ b/ext/tk/lib/multi-tk.rb
@@ -34,6 +34,64 @@ 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
class MultiTkIp_OK < Exception
def self.send(thread, ret=nil)
@@ -54,6 +112,8 @@ MultiTkIp_OK.freeze
################################################
# methods for construction
class MultiTkIp
+ BASE_DIR = File.dirname(__FILE__)
+
@@SLAVE_IP_ID = ['slave'.freeze, '0'.taint].freeze
@@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){
def self.new(target, ret)
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
undef :instance_eval
end
}
+
@@DEFAULT_MASTER.freeze # defend against modification
######################################
@@ -1115,6 +1245,8 @@ class MultiTkIp
@threadgroup = ThreadGroup.new
+ @pseudo_toplevel = [false, nil]
+
@cmd_queue = Queue.new
=begin
@@ -1424,6 +1556,17 @@ class MultiTkIp
}
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)
#init_ip_env.each{|script| self.eval_proc{script.call(self)}}
init_ip_env.each{|script| self._init_ip_env(script)}
@@ -1450,9 +1593,21 @@ class MultiTkIp
__getip._tk_table_list[id]
end
def self.create_table
- #if __getip.slave?
- # raise SecurityError, "slave-IP has no permission creating a new table"
- #end
+ if __getip.slave?
+ begin
+ 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
obj = Object.new
@@TK_TABLE_LIST << obj
@@ -1468,15 +1623,48 @@ class MultiTkIp
def self.init_ip_env(script = Proc.new)
@@INIT_IP_ENV << script
- @@IP_TABLE.each{|tg, ip|
- ip._init_ip_env(script)
- }
+ if __getip.slave?
+ 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
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._add_tk_procs(name, args, body)
+ ip._remove_tk_procs(*names)
}
end
@@ -1565,6 +1753,46 @@ class MultiTkIp
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
class MultiTkIp
# instance method
diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb
index 4504d1d2ec..32360ac144 100644
--- a/ext/tk/lib/tk.rb
+++ b/ext/tk/lib/tk.rb
@@ -1192,8 +1192,22 @@ module TkCore
script.call(self)
end
def INTERP.add_tk_procs(name, args = nil, body = nil)
- @add_tk_procs << [name, args, body]
- self._invoke('proc', name, args, body) if args && body
+ if name.kind_of?(Array)
+ 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
def INTERP.init_ip_internal
ip = self
@@ -1285,6 +1299,8 @@ module TkCore
EOL
=end
+ at_exit{ INTERP.remove_tk_procs(TclTkLib::FINALIZE_PROC_NAME) }
+
EventFlag = TclTkLib::EventFlag
def callback_break
@@ -3886,12 +3902,14 @@ class TkObject<TkKernel
begin
cget(name)
rescue
- fail NameError,
- "undefined local variable or method `#{name}' for #{self.to_s}",
- error_at
+ super(id, *args)
+# fail NameError,
+# "undefined local variable or method `#{name}' for #{self.to_s}",
+# error_at
end
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
@@ -4563,7 +4581,7 @@ end
#Tk.freeze
module Tk
- RELEASE_DATE = '2006-07-03'.freeze
+ RELEASE_DATE = '2006-07-10'.freeze
autoload :AUTO_PATH, 'tk/variable'
autoload :TCL_PACKAGE_PATH, 'tk/variable'
diff --git a/ext/tk/lib/tk/font.rb b/ext/tk/lib/tk/font.rb
index f7ea973a71..be763b663b 100644
--- a/ext/tk/lib/tk/font.rb
+++ b/ext/tk/lib/tk/font.rb
@@ -859,10 +859,12 @@ class TkFont
begin
configinfo name
rescue
- fail NameError, "undefined local variable or method `#{name}' for #{self.to_s}", error_at
- end
+ super(id, *args)
+# fail NameError, "undefined local variable or method `#{name}' for #{self.to_s}", error_at
+# end
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
diff --git a/ext/tk/lib/tk/msgcat.rb b/ext/tk/lib/tk/msgcat.rb
index eee331650d..061e43fd89 100644
--- a/ext/tk/lib/tk/msgcat.rb
+++ b/ext/tk/lib/tk/msgcat.rb
@@ -130,7 +130,8 @@ class TkMsgCatalog < TkObject
self.set_translation(loc, *args)
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
diff --git a/ext/tk/lib/tkextlib/itk/incr_tk.rb b/ext/tk/lib/tkextlib/itk/incr_tk.rb
index d37fd12a7c..0626536e36 100644
--- a/ext/tk/lib/tkextlib/itk/incr_tk.rb
+++ b/ext/tk/lib/tkextlib/itk/incr_tk.rb
@@ -289,7 +289,8 @@ module Tk
end
# unknown method
- fail RuntimeError, "unknown method '#{name}' for #{self.inspect}"
+ super(id, *args)
+ # fail RuntimeError, "unknown method '#{name}' for #{self.inspect}"
end
def tk_send(cmd, *rest)
diff --git a/ext/tk/sample/demos-en/widget b/ext/tk/sample/demos-en/widget
index cb60bc86ea..3c50582211 100644
--- a/ext/tk/sample/demos-en/widget
+++ b/ext/tk/sample/demos-en/widget
@@ -509,12 +509,93 @@ else # ver >= 8.4
alias showVars showVars2
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
+ Module.new.instance_eval{extend PseudoToplevel_Evaluable}
# binding
- Module.new.instance_eval{binding}
+ # Module.new.instance_eval{binding}
end
private :_null_binding
+def eval_samplecode(code)
+ Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } }.run
+ Tk.update
+end
+
# invoke --
# This procedure is called when the user clicks on a demo description.
# It is responsible for invoking the demonstration.
@@ -529,8 +610,9 @@ def invoke(txt, idx)
cursor = txt.cget('cursor')
txt.cursor('watch')
Tk.update
- eval(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, _null_binding)
- Tk.update
+ # eval(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, _null_binding)
+ # Tk.update
+ eval_samplecode(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join)
txt.cursor(cursor)
$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)
TkButton.new(f) {
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)
# f.pack('side'=>'bottom', 'expand'=>'yes', 'fill'=>'x')
f.pack('side'=>'bottom', 'fill'=>'x')
@@ -690,7 +773,8 @@ def showCode2(demo)
:image=>$image['print'], :compound=>:left)
b_run = TkButton.new(bf, :text=>'Rerun Demo',
: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)
@@ -812,7 +896,7 @@ end
#
def aboutBox
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 " +
"( Copyright:: " +
"(c) 1996-1997 Sun Microsystems, Inc. / " +
@@ -837,11 +921,12 @@ ARGV.each{|cmd|
if cmd =~ /(.*).rb/
cmd = $1
end
- eval(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join,
- _null_binding)
+ #eval(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join,
+ # _null_binding)
+ eval_samplecode(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join)
}
if no_launcher
- $root.withdraw # hide root window
+ $root.withdraw # hide root window
Thread.start{
loop do
count = 0
diff --git a/ext/tk/sample/demos-jp/widget b/ext/tk/sample/demos-jp/widget
index 2156f841b7..11495dda54 100644
--- a/ext/tk/sample/demos-jp/widget
+++ b/ext/tk/sample/demos-jp/widget
@@ -551,12 +551,93 @@ else # ver >= 8.4
alias showVars showVars2
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
+ Module.new.instance_eval{extend PseudoToplevel_Evaluable}
# binding
- Module.new.instance_eval{binding}
+ # Module.new.instance_eval{binding}
end
private :_null_binding
+def eval_samplecode(code)
+ Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } }.run
+ Tk.update
+end
+
# テキスト上での click に対する動作
def invoke(txt, idx)
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')
txt.cursor('watch')
Tk.update
- eval(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, _null_binding)
- Tk.update
+ # eval(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, _null_binding)
+ # Tk.update
+ eval_samplecode(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join)
txt.cursor(cursor)
$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)
TkButton.new(f) {
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)
# f.pack('side'=>'bottom', 'expand'=>'yes', 'fill'=>'x')
f.pack('side'=>'bottom', 'fill'=>'x')
@@ -716,7 +799,8 @@ def showCode2(demo)
:image=>$image['print'], :compound=>:left)
b_run = TkButton.new(bf, :text=>'再実行',
: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)
@@ -842,7 +926,7 @@ end
#
def aboutBox
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 " +
"( Copyright:: " +
"(c) 1996-1997 Sun Microsystems, Inc. / " +
@@ -867,8 +951,9 @@ ARGV.each{|cmd|
if cmd =~ /(.*).rb/
cmd = $1
end
- eval(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join,
- _null_binding)
+ #eval(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join,
+ # _null_binding)
+ eval_samplecode(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join)
}
if no_launcher
$root.withdraw # hide root window
diff --git a/ext/tk/tcltklib.c b/ext/tk/tcltklib.c
index 5c986f1dcf..9a6449adc6 100644
--- a/ext/tk/tcltklib.c
+++ b/ext/tk/tcltklib.c
@@ -4,7 +4,7 @@
* Oct. 24, 1997 Y. Matsumoto
*/
-#define TCLTKLIB_RELEASE_DATE "2006-07-03"
+#define TCLTKLIB_RELEASE_DATE "2006-07-10"
#include "ruby.h"
#include "rubysig.h"
@@ -81,6 +81,8 @@ static char *finalize_hook_name = "INTERP_FINALIZE_HOOK";
static void ip_finalize _((Tcl_Interp*));
+static int at_exit = 0;
+
/* for callback break & continue */
static VALUE eTkCallbackReturn;
@@ -4362,6 +4364,33 @@ delete_slaves(ip)
/* 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
ip_finalize(ip)
Tcl_Interp *ip;
@@ -4407,6 +4436,29 @@ ip_finalize(ip)
/* delete slaves */
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 */
#if 0
DUMP1("check `destroy'");
@@ -4429,7 +4481,7 @@ ip_finalize(ip)
/* call 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);
ruby_debug = Qfalse;
ruby_verbose = Qnil;
@@ -4684,7 +4736,6 @@ ip_CallWhenDeleted(clientData, ip)
rb_thread_critical = thr_crit_bup;
}
-
/* initialize interpreter */
static VALUE
ip_init(argc, argv, self)
@@ -7929,6 +7980,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_thread?",
lib_evloop_thread_p, 0);
@@ -8065,6 +8118,10 @@ Init_tcltklib()
/* --------------------------------------------------------------- */
+ rb_eval_string("at_exit{ TclTkLib._mark_at_exit }");
+
+ /* --------------------------------------------------------------- */
+
ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0);
switch(ret) {
case TCLTK_STUBS_OK: