1
0
Fork 0
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:
nagai 2006-07-10 09:52:30 +00:00
parent a1a07fbfa1
commit d2271cbdd1
9 changed files with 543 additions and 40 deletions

View file

@ -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>
* sample/test.rb: update test suites.

View file

@ -33,6 +33,64 @@ class << TclTkIp
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
@ -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,17 +1623,50 @@ 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)
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._remove_tk_procs(*names)
}
end
def self.init_ip_internal
__getip._init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS)
@ -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

View file

@ -1192,9 +1192,23 @@ module TkCore
script.call(self)
end
def INTERP.add_tk_procs(name, args = nil, body = nil)
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
@init_ip_env.each{|script| script.call(ip)}
@ -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'

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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,8 +921,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

View file

@ -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

View file

@ -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;
@ -4358,6 +4360,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;
@ -4403,6 +4432,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'");
@ -4425,7 +4477,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;
@ -4680,7 +4732,6 @@ ip_CallWhenDeleted(clientData, ip)
rb_thread_critical = thr_crit_bup;
}
/* initialize interpreter */
static VALUE
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_thread?",
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);
switch(ret) {
case TCLTK_STUBS_OK: