diff options
Diffstat (limited to 'ext/tk/lib/tk.rb')
-rw-r--r-- | ext/tk/lib/tk.rb | 255 |
1 files changed, 170 insertions, 85 deletions
diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb index 49e4ca2564..b071bf5be8 100644 --- a/ext/tk/lib/tk.rb +++ b/ext/tk/lib/tk.rb @@ -15,7 +15,9 @@ require 'thread' class TclTkIp # backup original (without encoding) _eval and _invoke alias _eval_without_enc _eval + alias __eval__ _eval alias _invoke_without_enc _invoke + alias __invoke__ _invoke def _ip_id_ # for RemoteTkIp @@ -28,8 +30,8 @@ class TclTkIp def initialize(*args) __initialize__(*args) - @force_default_encoding ||= [false].taint - @encoding ||= [nil].taint + @force_default_encoding ||= TkUtil.untrust([false]) + @encoding ||= TkUtil.untrust([nil]) def @encoding.to_s; self.join(nil); end end end @@ -39,8 +41,8 @@ module TkComm include TkUtil extend TkUtil - WidgetClassNames = {}.taint - TkExtlibAutoloadModule = [].taint + WidgetClassNames = TkUtil.untrust({}) + TkExtlibAutoloadModule = TkUtil.untrust([]) # None = Object.new ### --> definition is moved to TkUtil module # def None.to_s @@ -50,7 +52,10 @@ module TkComm #Tk_CMDTBL = {} #Tk_WINDOWS = {} - Tk_IDs = ["00000".taint, "00000".taint] # [0]-cmdid, [1]-winid + Tk_IDs = [ + TkUtil.untrust("00000"), # [0]-cmdid + TkUtil.untrust("00000") # [1]-winid + ] Tk_IDs.instance_eval{ @mutex = Mutex.new def mutex; @mutex; end @@ -70,7 +75,7 @@ module TkComm Tk_WINDOWS.freeze self.instance_eval{ - @cmdtbl = [].taint + @cmdtbl = TkUtil.untrust([]) } unless const_defined?(:GET_CONFIGINFO_AS_ARRAY) @@ -113,15 +118,22 @@ module TkComm gen_class_name = ruby_class_name classname_def = '' else # ruby_class == nil - mods = TkExtlibAutoloadModule.find_all{|m| m.const_defined?(tk_class)} - mods.each{|mod| - begin - mod.const_get(tk_class) # auto_load - break if (ruby_class = WidgetClassNames[tk_class]) - rescue LoadError - # ignore load error - end - } + if Tk.const_defined?(tk_class) + mod.const_get(tk_class) # auto_load + ruby_class = WidgetClassNames[tk_class] + end + + unless ruby_class + mods = TkExtlibAutoloadModule.find_all{|m| m.const_defined?(tk_class)} + mods.each{|mod| + begin + mod.const_get(tk_class) # auto_load + break if (ruby_class = WidgetClassNames[tk_class]) + rescue LoadError + # ignore load error + end + } + end unless ruby_class std_class = 'Tk' << tk_class @@ -131,6 +143,14 @@ module TkComm end end + unless ruby_class + if Tk.const_defined?('TOPLEVEL_ALIASES') && + Tk::TOPLEVEL_ALIASES.const_defined?(std_class) + Tk::TOPLEVEL_ALIASES.const_get(std_class) # auto_load + ruby_class = WidgetClassNames[tk_class] + end + end + if ruby_class # found ruby_class_name = ruby_class.name @@ -613,11 +633,35 @@ end val end end - private :bool, :number, :string, :num_or_str - private :list, :simplelist, :window, :procedure - module_function :bool, :number, :num_or_str, :string + private :bool, :number, :num_or_str, :num_or_nil, :string + private :list, :simplelist, :window, :image_obj, :procedure + module_function :bool, :number, :num_or_str, :num_or_nil, :string module_function :list, :simplelist, :window, :image_obj, :procedure + if (RUBY_VERSION.split('.').map{|n| n.to_i} <=> [1,8,7]) < 0 + def slice_ary(ary, size) + sliced = [] + wk_ary = ary.dup + until wk_ary.size.zero? + sub_ary = [] + size.times{ sub_ary << wk_ary.shift } + yield(sub_ary) if block_given? + sliced << sub_ary + end + (block_given?)? ary: sliced + end + else + def slice_ary(ary, size, &b) + if b + ary.each_slice(size, &b) + else + ary.each_slice(size).to_a + end + end + end + private :slice_ary + module_function :slice_ary + def subst(str, *opts) # opts := :nobackslashes | :nocommands | novariables tk_call('subst', @@ -803,7 +847,7 @@ end TkCore::INTERP.tk_cmd_tbl[id] = TkCore::INTERP.get_cb_entry(cmd) end @cmdtbl = [] unless defined? @cmdtbl - @cmdtbl.taint unless @cmdtbl.tainted? + TkUtil.untrust(@cmdtbl) unless @cmdtbl.tainted? @cmdtbl.push id if local_cmdtbl && local_cmdtbl.kind_of?(Array) @@ -1130,30 +1174,42 @@ module TkCore opts = '' end - if WITH_RUBY_VM ### check Ruby 1.9 !!!!!!! - # *** NEED TO FIX *** - ip = TclTkIp.new(name, opts) - if ip._invoke_without_enc('tk', 'windowingsystem') == 'aqua' && - (TclTkLib.get_version <=> [8,4,TclTkLib::RELEASE_TYPE::FINAL,9]) > 0 - # *** KNOWN BUG *** - # Main event loop thread of TkAqua (> Tk8.4.9) must be the main - # application thread. So, ruby1.9 users must call Tk.mainloop on - # the main application thread. - RUN_EVENTLOOP_ON_MAIN_THREAD = true - INTERP = ip - else - unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD - RUN_EVENTLOOP_ON_MAIN_THREAD = false - end - if RUN_EVENTLOOP_ON_MAIN_THREAD + unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD + if WITH_RUBY_VM ### check Ruby 1.9 !!!!!!! + # *** NEED TO FIX *** + ip = TclTkIp.new(name, opts) + if ip._invoke_without_enc('tk', 'windowingsystem') == 'aqua' && + (TclTkLib.get_version<=>[8,4,TclTkLib::RELEASE_TYPE::FINAL,6]) > 0 + # *** KNOWN BUG *** + # Main event loop thread of TkAqua (> Tk8.4.9) must be the main + # application thread. So, ruby1.9 users must call Tk.mainloop on + # the main application thread. + # + # *** ADD (2009/05/10) *** + # In some cases (I don't know the description of conditions), + # TkAqua 8.4.7 has a same kind of hang-up trouble. + # So, if 8.4.7 or later, set RUN_EVENTLOOP_ON_MAIN_THREAD to true. + # When you want to control this mode, please call the following + # (set true/false as you want) before "require 'tk'". + # ---------------------------------------------------------- + # module TkCore; RUN_EVENTLOOP_ON_MAIN_THREAD = true; end + # ---------------------------------------------------------- + # + RUN_EVENTLOOP_ON_MAIN_THREAD = true INTERP = ip else - ip.delete + unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD + RUN_EVENTLOOP_ON_MAIN_THREAD = false + end + if RUN_EVENTLOOP_ON_MAIN_THREAD + INTERP = ip + else + ip.delete + end end - end - ip = nil - else - unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD + ip = nil + + else # Ruby 1.8.x RUN_EVENTLOOP_ON_MAIN_THREAD = false end end @@ -1183,13 +1239,29 @@ module TkCore #sleep begin - Thread.current[:status].value = TclTkLib.mainloop(true) - rescue Exception=>e - Thread.current[:status].value = e + begin + #TclTkLib.mainloop_abort_on_exception = false + #Thread.current[:status].value = TclTkLib.mainloop(true) + interp.mainloop_abort_on_exception = true + Thread.current[:status].value = interp.mainloop(true) + rescue SystemExit=>e + Thread.current[:status].value = e + rescue Exception=>e + Thread.current[:status].value = e + retry if interp.has_mainwindow? + ensure + INTERP_MUTEX.synchronize{ INTERP_ROOT_CHECK.broadcast } + end + + #Thread.current[:status].value = TclTkLib.mainloop(false) + Thread.current[:status].value = interp.mainloop(false) + ensure - INTERP_MUTEX.synchronize{ INTERP_ROOT_CHECK.broadcast } + # interp must be deleted before the thread for interp is dead. + # If not, raise Tcl_Panic on Tcl_AsyncDelete because async handler + # deleted by the wrong thread. + interp.delete end - Thread.current[:status].value = TclTkLib.mainloop(false) } until INTERP_THREAD[:interp] @@ -1210,10 +1282,11 @@ module TkCore end INTERP.instance_eval{ - # @tk_cmd_tbl = {}.taint - @tk_cmd_tbl = Hash.new{|hash, key| - fail IndexError, "unknown command ID '#{key}'" - }.taint + # @tk_cmd_tbl = TkUtil.untrust({}) + @tk_cmd_tbl = + TkUtil.untrust(Hash.new{|hash, key| + fail IndexError, "unknown command ID '#{key}'" + }) def @tk_cmd_tbl.[]=(idx,val) if self.has_key?(idx) && Thread.current.group != ThreadGroup::Default fail SecurityError,"cannot change the entried command" @@ -1221,15 +1294,15 @@ module TkCore super(idx,val) end - @tk_windows = {}.taint + @tk_windows = TkUtil.untrust({}) - @tk_table_list = [].taint + @tk_table_list = TkUtil.untrust([]) - @init_ip_env = [].taint # table of Procs - @add_tk_procs = [].taint # table of [name, args, body] + @init_ip_env = TkUtil.untrust([]) # table of Procs + @add_tk_procs = TkUtil.untrust([]) # table of [name, args, body] - @force_default_encoding ||= [false].taint - @encoding ||= [nil].taint + @force_default_encoding ||= TkUtil.untrust([false]) + @encoding ||= TkUtil.untrust([nil]) def @encoding.to_s; self.join(nil); end @cb_entry_class = Class.new(TkCallbackEntry){ @@ -1283,7 +1356,7 @@ module TkCore end def INTERP.create_table id = @tk_table_list.size - (tbl = {}).tainted? || tbl.taint + (tbl = {}).tainted? || TkUtil.untrust(tbl) @tk_table_list << tbl # obj = Object.new # obj.instance_eval <<-EOD @@ -1321,7 +1394,8 @@ module TkCore @add_tk_procs.delete_if{|elem| elem.kind_of?(Array) && elem[0].to_s == name } - self._invoke('rename', name, '') + #self._invoke('rename', name, '') + self.__invoke__('rename', name, '') } end def INTERP.init_ip_internal @@ -1704,11 +1778,14 @@ module TkCore elsif TkCore::RUN_EVENTLOOP_ON_MAIN_THREAD # if TclTkLib::WINDOWING_SYSTEM == 'aqua' && - if TkCore::INTERP._invoke_without_enc('tk','windowingsystem')=='aqua' && - Thread.current != Thread.main && - (TclTkLib.get_version <=> [8,4,TclTkLib::RELEASE_TYPE::FINAL,9]) > 0 - raise RuntimeError, - "eventloop on TkAqua ( > Tk8.4.9 ) works on the main thread only" + #if TkCore::INTERP._invoke_without_enc('tk','windowingsystem')=='aqua' && + # Thread.current != Thread.main && + # (TclTkLib.get_version <=> [8,4,TclTkLib::RELEASE_TYPE::FINAL,9]) > 0 + # raise RuntimeError, + # "eventloop on TkAqua ( > Tk8.4.9 ) works on the main thread only" + #end + if Thread.current != Thread.main + raise RuntimeError, "Tk.mainloop is allowed on the main thread only" end TclTkLib.mainloop(check_root) @@ -1911,7 +1988,7 @@ module TkCore puts 'invoke args => ' + args.inspect if $DEBUG ### print "=> ", args.join(" ").inspect, "\n" if $DEBUG begin - # res = INTERP._invoke(*args).taint + # res = TkUtil.untrust(INTERP._invoke(*args)) # res = INTERP._invoke(enc_mode, *args) res = _ip_invoke_core(enc_mode, *args) # >>>>> _invoke returns a TAINTED string <<<<< @@ -1919,7 +1996,7 @@ module TkCore # err = $! begin args.unshift "unknown" - #res = INTERP._invoke(*args).taint + #res = TkUtil.untrust(INTERP._invoke(*args)) #res = INTERP._invoke(enc_mode, *args) res = _ip_invoke_core(enc_mode, *args) # >>>>> _invoke returns a TAINTED string <<<<< @@ -3028,7 +3105,7 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) =begin if ext_enc_obj == Tk::Encoding::UNKNOWN - if defind? DEFAULT_TK_ENCODING + if defined? DEFAULT_TK_ENCODING if DEFAULT_TK_ENCODING.kind_of?(::Encoding) tk_enc_name = DEFAULT_TK_ENCODING.name tksys_enc_name = DEFAULT_TK_ENCODING.name @@ -3126,7 +3203,7 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) #if ext_enc_name && ext_enc_name != tksys_enc_name int_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(int_enc_obj) if int_enc_name - # use default_external + # use default_internal enc_name = int_enc_name else # use Tk.encoding_system @@ -3279,10 +3356,10 @@ module TkTreatFont TkFont.init_widget_font(pathname, *__confinfo_cmd) else fonts = {} - optkeys.each{|key| - key = key.to_s - pathname = [win, tag, key].join(';') - fonts[key] = + optkeys.each{|k| + k = k.to_s + pathname = [win, tag, k].join(';') + fonts[k] = TkFont.used_on(pathname) || TkFont.init_widget_font(pathname, *__confinfo_cmd) } @@ -3407,7 +3484,7 @@ module TkTreatFont if fobj.kind_of?(TkFont) if ltn.kind_of?(TkFont) conf = {} - ltn.latin_configinfo.each{|key,val| conf[key] = val} + ltn.latin_configinfo.each{|k,val| conf[k] = val} if keys fobj.latin_configure(conf.update(keys)) else @@ -3467,7 +3544,7 @@ module TkTreatFont if fobj.kind_of?(TkFont) if knj.kind_of?(TkFont) conf = {} - knj.kanji_configinfo.each{|key,val| conf[key] = val} + knj.kanji_configinfo.each{|k,val| conf[k] = val} if keys fobj.kanji_configure(conf.update(keys)) else @@ -3701,11 +3778,17 @@ module TkConfigMethod val end + def cget_tkstring(option) + opt = option.to_s + fail ArgumentError, "Invalid option `#{option.inspect}'" if opt.length == 0 + tk_call_without_enc(*(__cget_cmd << "-#{opt}")) + end + def __cget_core(slot) orig_slot = slot slot = slot.to_s - if slot.length == 0 + if slot.length == 0 fail ArgumentError, "Invalid option `#{orig_slot.inspect}'" end @@ -4106,7 +4189,8 @@ module TkConfigMethod else # conf = tk_split_list(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")))) - conf = tk_split_list(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), 0, false, true) + # conf = tk_split_list(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), 0, false, true) + conf = tk_split_list(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), 1, false, true) end conf[__configinfo_struct[:key]] = conf[__configinfo_struct[:key]][1..-1] @@ -4296,8 +4380,8 @@ module TkConfigMethod end } - __methodcall_optkeys.each{|optkey, method| - ret << [optkey.to_s, '', '', '', self.__send__(method)] + __methodcall_optkeys.each{|optkey, m| + ret << [optkey.to_s, '', '', '', self.__send__(m)] } ret @@ -4335,7 +4419,7 @@ module TkConfigMethod if slot slot = slot.to_s - alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot} + alias_name, real_name = __optkey_aliases.find{|k,var| k.to_s == slot} if real_name slot = real_name.to_s end @@ -4682,8 +4766,8 @@ module TkConfigMethod end } - __methodcall_optkeys.each{|optkey, method| - ret[optkey.to_s] = ['', '', '', self.__send__(method)] + __methodcall_optkeys.each{|optkey, m| + ret[optkey.to_s] = ['', '', '', self.__send__(m)] } ret @@ -4721,18 +4805,18 @@ module TkConfigMethod "there is a configure alias loop about '#{org_slot}'" else ret = {} - configinfo().each{|conf| + configinfo().each{|cnf| if ( ! __configinfo_struct[:alias] \ - || conf.size > __configinfo_struct[:alias] + 1 ) - ret[conf[0]] = conf[-1] + || cnf.size > __configinfo_struct[:alias] + 1 ) + ret[cnf[0]] = cnf[-1] end } ret end else # ! TkComm::GET_CONFIGINFO_AS_ARRAY ret = {} - configinfo(slot).each{|key, conf| - ret[key] = conf[-1] if conf.kind_of?(Array) + configinfo(slot).each{|key, cnf| + ret[key] = cnf[-1] if cnf.kind_of?(Array) } ret end @@ -4864,6 +4948,7 @@ class TkWindow<TkObject include TkWinfo extend TkBindCore include Tk::Wm_for_General + include Tk::Busy @@WIDGET_INSPECT_FULL = false def TkWindow._widget_inspect_full_? @@ -5551,7 +5636,7 @@ TkWidget = TkWindow #Tk.freeze module Tk - RELEASE_DATE = '2009-01-13'.freeze + RELEASE_DATE = '2009-07-12'.freeze autoload :AUTO_PATH, 'tk/variable' autoload :TCL_PACKAGE_PATH, 'tk/variable' |