summaryrefslogtreecommitdiff
path: root/ext/tk/lib
diff options
context:
space:
mode:
authornagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-07-10 09:52:30 +0000
committernagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-07-10 09:52:30 +0000
commit6e0e4baf29ddfe8d3d4fb76b0dc1619abb5e5bef (patch)
tree05109d1d150a320fc59a389a4921be5a18a0d66c /ext/tk/lib
parent5ed246f1d37571ce482bf3fcbb28457d8dd5cf06 (diff)
* 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/branches/ruby_1_8@10505 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/tk/lib')
-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
5 files changed, 270 insertions, 20 deletions
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)