diff options
Diffstat (limited to 'ext/tk/lib')
77 files changed, 5083 insertions, 1392 deletions
diff --git a/ext/tk/lib/multi-tk.rb b/ext/tk/lib/multi-tk.rb index ed936bf1a..fd9a86388 100644 --- a/ext/tk/lib/multi-tk.rb +++ b/ext/tk/lib/multi-tk.rb @@ -114,7 +114,14 @@ MultiTkIp_OK.freeze class MultiTkIp BASE_DIR = File.dirname(__FILE__) - @@SLAVE_IP_ID = ['slave'.freeze, '0'.taint].freeze + WITH_RUBY_VM = Object.const_defined?(:VM) && ::VM.class == Class + WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class + + (@@SLAVE_IP_ID = ['slave'.freeze, '0'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } @@IP_TABLE = {}.taint unless defined?(@@IP_TABLE) @@ -126,7 +133,11 @@ class MultiTkIp unless defined?(@@TK_CMD_TBL) @@TK_CMD_TBL = Object.new.taint - @@TK_CMD_TBL.instance_variable_set('@tbl', {}.taint) + # @@TK_CMD_TBL.instance_variable_set('@tbl', {}.taint) + @@TK_CMD_TBL.instance_variable_set('@tbl', Hash.new{|hash,key| + fail IndexError, + "unknown command ID '#{key}'" + }.taint) class << @@TK_CMD_TBL allow = [ @@ -573,7 +584,11 @@ class MultiTkIp # raise exception begin bt = _toUTF8(e.backtrace.join("\n")) - bt.instance_variable_set(:@encoding, 'utf-8') + if MultiTkIp::WITH_ENCODING + bt.force_encoding('utf-8') + else + bt.instance_variable_set(:@encoding, 'utf-8') + end rescue Exception bt = e.backtrace.join("\n") end @@ -695,7 +710,10 @@ class MultiTkIp ###################################### - WITH_RUBY_VM = Object.const_defined?(:VM) && ::VM.class == Class + unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD + ### Ruby 1.9 !!!!!!!!!!!!!!!!!!!!!!!!!! + RUN_EVENTLOOP_ON_MAIN_THREAD = false + end if self.const_defined? :DEFAULT_MASTER_NAME name = DEFAULT_MASTER_NAME.to_s @@ -725,13 +743,24 @@ class MultiTkIp fail ArgumentError, "expecting a Hash object for the 2nd argument" end - unless WITH_RUBY_VM + if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!! @interp = TclTkIp.new(name, _keys2opts(keys)) else ### Ruby 1.9 !!!!!!!!!!! @interp_thread = Thread.new{ - Thread.current[:interp] = interp = TclTkIp.new(name, _keys2opts(keys)) + current = Thread.current + current[:interp] = interp = TclTkIp.new(name, _keys2opts(keys)) #sleep - interp.mainloop(true) + current[:mutex] = mutex = Mutex.new + current[:root_check] = cond_var = ConditionVariable.new + + begin + current[:status] = interp.mainloop(true) + rescue Exception=>e + current[:status] = e + ensure + mutex.synchronize{ cond_var.broadcast } + end + current[:status] = interp.mainloop(false) } until @interp_thread[:interp] Thread.pass @@ -976,9 +1005,11 @@ class MultiTkIp private :_parse_slaveopts def _create_slave_ip_name - name = @@SLAVE_IP_ID.join('') - @@SLAVE_IP_ID[1].succ! - name.freeze + @@SLAVE_IP_ID.mutex.synchronize{ + name = @@SLAVE_IP_ID.join('') + @@SLAVE_IP_ID[1].succ! + name.freeze + } end private :_create_slave_ip_name @@ -1309,11 +1340,11 @@ class MultiTkIp @@DEFAULT_MASTER.assign_receiver_and_watchdog(self) @@IP_TABLE[@threadgroup] = self - _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS) @@TK_TABLE_LIST.size.times{ (tbl = {}).tainted? || tbl.taint @tk_table_list << tbl } + _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS) class << self undef :instance_eval @@ -1391,8 +1422,13 @@ class << MultiTkIp alias __new new private :__new - def new_master(safe=nil, keys={}) + if MultiTkIp::WITH_RUBY_VM + #### TODO !!!!!! + fail RuntimeError, + 'sorry, still not support multiple master-interpreters on Ruby VM' + end + if safe.kind_of?(Hash) keys = safe elsif safe.kind_of?(Integer) @@ -1609,8 +1645,13 @@ class MultiTkIp return if slave? names.each{|name| name = name.to_s + + return if @interp.deleted? @interp._invoke('rename', name, '') + + return if @interp.deleted? @interp._invoke('interp', 'slaves').split.each{|slave| + return if @interp.deleted? @interp._invoke('interp', 'alias', slave, name, '') rescue nil } } @@ -1660,11 +1701,16 @@ class MultiTkIp id = @@TK_TABLE_LIST.size obj = Object.new @@TK_TABLE_LIST << obj - obj.instance_eval <<-EOD + obj.instance_variable_set(:@id, id) + obj.instance_variable_set(:@mutex, Mutex.new) + obj.instance_eval{ + def self.mutex + @mutex + end def self.method_missing(m, *args) - MultiTkIp.tk_object_table(#{id}).__send__(m, *args) + MultiTkIp.tk_object_table(@id).__send__(m, *args) end - EOD + } obj.freeze @@IP_TABLE.each{|tg, ip| ip._add_new_tables } return obj @@ -2797,9 +2843,10 @@ class MultiTkIp i = -1 brace = 1 str.each_byte {|c| + c = c.chr i += 1 - brace += 1 if c == ?{ - brace -= 1 if c == ?} + brace += 1 if c == '{' + brace -= 1 if c == '}' break if brace == 0 } if i == 0 @@ -3238,15 +3285,44 @@ end # encoding convert +class << MultiTkIp + def encoding_table + __getip.encoding_table + end +end class MultiTkIp - def encoding + def encoding_table + @interp.encoding_table + end + + def force_default_encoding=(mode) raise SecurityError, "no permission to manipulate" unless self.manipulable? - @interp.encoding + @interp.force_default_encoding = mode end + def force_default_encoding? + raise SecurityError, "no permission to manipulate" unless self.manipulable? + @interp.force_default_encoding? + end + + def default_encoding=(enc) + raise SecurityError, "no permission to manipulate" unless self.manipulable? + @interp.default_encoding = enc + end + def encoding=(enc) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.encoding = enc end + def encoding_name + raise SecurityError, "no permission to manipulate" unless self.manipulable? + @interp.encoding_name + end + def encoding_obj + raise SecurityError, "no permission to manipulate" unless self.manipulable? + @interp.encoding_obj + end + alias encoding encoding_name + alias default_encoding encoding_name def encoding_convertfrom(str, enc=None) raise SecurityError, "no permission to manipulate" unless self.manipulable? @@ -3264,12 +3340,28 @@ end # remove methods for security class MultiTkIp + INTERP_THREAD = @@DEFAULT_MASTER.instance_variable_get('@interp_thread') + INTERP_MUTEX = INTERP_THREAD[:mutex] + INTERP_ROOT_CHECK = INTERP_THREAD[:root_check] + # undef_method :instance_eval undef_method :instance_variable_get undef_method :instance_variable_set end - +module TkCore + if MultiTkIp::WITH_RUBY_VM && + ! MultiTkIp::RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!! + INTERP_THREAD = MultiTkIp::INTERP_THREAD + INTERP_MUTEX = MultiTkIp::INTERP_MUTEX + INTERP_ROOT_CHECK = MultiTkIp::INTERP_ROOT_CHECK + end +end +class MultiTkIp + remove_const(:INTERP_THREAD) + remove_const(:INTERP_MUTEX) + remove_const(:INTERP_ROOT_CHECK) +end # end of MultiTkIp definition # defend against modification diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb index d80271a32..0d00ecf20 100644 --- a/ext/tk/lib/tk.rb +++ b/ext/tk/lib/tk.rb @@ -9,6 +9,9 @@ require 'tkutil' # autoload require 'tk/autoload' +# for Mutex +require 'thread' + class TclTkIp # backup original (without encoding) _eval and _invoke alias _eval_without_enc _eval @@ -36,7 +39,12 @@ module TkComm #Tk_CMDTBL = {} #Tk_WINDOWS = {} - Tk_IDs = ["00000".taint, "00000".taint].freeze # [0]-cmdid, [1]-winid + Tk_IDs = ["00000".taint, "00000".taint] # [0]-cmdid, [1]-winid + Tk_IDs.instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } # for backward compatibility Tk_CMDTBL = Object.new @@ -217,7 +225,9 @@ module TkComm TkCore::INTERP.tk_windows[val]? TkCore::INTERP.tk_windows[val] : _genobj_for_tkwidget(val) when /\Ai(_\d+_)?\d+\z/ - TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val + TkImage::Tk_IMGTBL.mutex.synchronize{ + TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val + } when /\A-?\d+\.?\d*(e[-+]?\d+)?\z/ val.to_f when /\\ / @@ -334,6 +344,8 @@ if USE_TCLs_LIST_FUNCTIONS if dst_enc != true && dst_enc != false if (s_enc = s.instance_variable_get(:@encoding)) s_enc = s_enc.to_s + elsif TkCore::WITH_ENCODING + s_enc = s.encoding.name else s_enc = sys_enc end @@ -346,11 +358,20 @@ if USE_TCLs_LIST_FUNCTIONS if sys_enc && dst_enc dst.map!{|s| _toUTF8(s)} ret = TkCore::INTERP._merge_tklist(*dst) - if dst_enc.kind_of?(String) - ret = _fromUTF8(ret, dst_enc) - ret.instance_variable_set(:@encoding, dst_enc) - else - ret.instance_variable_set(:@encoding, 'utf-8') + if TkCore::WITH_ENCODING + if dst_enc.kind_of?(String) + ret = _fromUTF8(ret, dst_enc) + ret.force_encoding(dst_enc) + else + ret.force_encoding('utf-8') + end + else # without encoding + if dst_enc.kind_of?(String) + ret = _fromUTF8(ret, dst_enc) + ret.instance_variable_set(:@encoding, dst_enc) + else + ret.instance_variable_set(:@encoding, 'utf-8') + end end ret else @@ -410,46 +431,6 @@ else tk_split_sublist(token, depth - 1) } end -=begin - def tk_split_list(str) - return [] if str == "" - idx = str.index('{') - while idx and idx > 0 and str[idx-1] == ?\\ - idx = str.index('{', idx+1) - end - unless idx - list = tk_tcl2ruby(str) - unless Array === list - list = [list] - end - return list - end - - list = tk_tcl2ruby(str[0,idx]) - list = [] if list == "" - str = str[idx+1..-1] - i = -1 - escape = false - brace = 1 - str.each_byte {|c| - i += 1 - brace += 1 if c == ?{ && !escape - brace -= 1 if c == ?} && !escape - escape = (c == ?\\) - break if brace == 0 - } - if str.size == i + 1 - return tk_split_list(str[0, i]) - end - if str[0, i] == ' ' - list.push ' ' - else - list.push tk_split_list(str[0, i]) - end - list += tk_split_list(str[i+1..-1]) - list - end -=end def tk_split_simplelist(str, src_enc=true, dst_enc=true) return [] if str == "" @@ -600,7 +581,9 @@ end end def image_obj(val) if val =~ /^i(_\d+_)?\d+$/ - TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val + TkImage::Tk_IMGTBL.mutex.synchronize{ + TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val + } else val end @@ -782,10 +765,12 @@ end id = "c" + TkCore::INTERP._ip_id_ + TkComm::Tk_IDs[0] end def _next_cmd_id - id = _curr_cmd_id - #Tk_IDs[0] += 1 - TkComm::Tk_IDs[0].succ! - id + TkComm::Tk_IDs.mutex.synchronize{ + id = _curr_cmd_id + #Tk_IDs[0] += 1 + TkComm::Tk_IDs[0].succ! + id + } end private :_curr_cmd_id, :_next_cmd_id module_function :_curr_cmd_id, :_next_cmd_id @@ -855,8 +840,10 @@ end return TkCore::INTERP.tk_windows[@path] = self end else - name = "w" + TkCore::INTERP._ip_id_ + Tk_IDs[1] - Tk_IDs[1].succ! + Tk_IDs.mutex.synchronize{ + name = "w" + TkCore::INTERP._ip_id_ + Tk_IDs[1] + Tk_IDs[1].succ! + } end if !ppath or ppath == '.' @path = '.' + name @@ -935,7 +922,12 @@ module TkComm def _bindinfo(what, context=nil) if context - tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]).each_line.collect {|cmdline| + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + enum_obj = tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]).each_line + else + enum_obj = tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]) + end + enum_obj.collect {|cmdline| =begin if cmdline =~ /^rb_out\S* (c(?:_\d+_)?\d+)\s+(.*)$/ #[Tk_CMDTBL[$1], $2] @@ -1106,10 +1098,9 @@ module TkCore opts = '' end - if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### Ruby 1.9 !!!!!!!!!!! + if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!! INTERP = TclTkIp.new(name, opts) else - require 'thread' INTERP_MUTEX = Mutex.new INTERP_ROOT_CHECK = ConditionVariable.new INTERP_THREAD = Thread.new{ @@ -1146,7 +1137,10 @@ module TkCore end INTERP.instance_eval{ - @tk_cmd_tbl = {}.taint + # @tk_cmd_tbl = {}.taint + @tk_cmd_tbl = Hash.new{|hash, key| + fail IndexError, "unknown command ID '#{key}'" + }.taint def @tk_cmd_tbl.[]=(idx,val) if self.has_key?(idx) && Thread.current.group != ThreadGroup::Default fail SecurityError,"cannot change the entried command" @@ -1197,6 +1191,10 @@ module TkCore class Tk_OBJECT_TABLE def initialize(id) @id = id + @mutex = Mutex.new + end + def mutex + @mutex end def method_missing(m, *args, &b) TkCore::INTERP.tk_object_table(@id).__send__(m, *args, &b) @@ -1382,7 +1380,11 @@ module TkCore "\n---< backtrace of Ruby side >-----\n" + _toUTF8(e.backtrace.join("\n")) + "\n---< backtrace of Tk side >-------" - msg.instance_variable_set(:@encoding, 'utf-8') + if TkCore::WITH_ENCODING + msg.force_encoding('utf-8') + else + msg.instance_variable_set(:@encoding, 'utf-8') + end rescue Exception msg = e.class.inspect + ': ' + e.message + "\n" + "\n---< backtrace of Ruby side >-----\n" + @@ -1438,6 +1440,11 @@ module TkCore end def after(ms, cmd=Proc.new) + cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret}) + tk_call_without_enc("after",ms,cmdid) # return id + end +=begin + def after(ms, cmd=Proc.new) crit_bup = Thread.critical Thread.critical = true @@ -1460,8 +1467,14 @@ module TkCore # tk_call("after",ms,cmdid) # end end +=end def after_idle(cmd=Proc.new) + cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret}) + tk_call_without_enc('after','idle',cmdid) + end +=begin + def after_idle(cmd=Proc.new) crit_bup = Thread.critical Thread.critical = true @@ -1472,6 +1485,7 @@ module TkCore tk_call_without_enc('after','idle',cmdid) end +=end def after_cancel(afterId) tk_call_without_enc('after','cancel',afterId) @@ -1595,9 +1609,8 @@ module TkCore def mainloop(check_root = true) if !TkCore::WITH_RUBY_VM || TkCore::RUN_EVENTLOOP_ON_MAIN_THREAD - ### Ruby 1.9 !!!!!!!!!!! TclTkLib.mainloop(check_root) - else + else ### Ruby 1.9 !!!!! begin TclTkLib.set_eventloop_window_mode(true) if check_root @@ -2096,6 +2109,27 @@ module Tk tk_call_without_enc('destroy', '.') end + ################################################ + + def Tk.sleep(ms = nil, id = nil) + if id + var = (id.kind_of?(TkVariable))? id: TkVarAccess.new(id.to_s) + else + var = TkVariable.new + end + + var.value = tk_call_without_enc('after', ms, proc{ var.value = 0 }) if ms + var.thread_wait + ms + end + + def Tk.wakeup(id) + ((id.kind_of?(TkVariable))? id: TkVarAccess.new(id.to_s)).value = 0 + nil + end + + ################################################ + def Tk.pack(*args) TkPack.configure(*args) end @@ -2271,16 +2305,432 @@ end # convert kanji string to/from utf-8 ########################################### if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) + module Tk + module Encoding + extend Encoding + + TkCommandNames = ['encoding'.freeze].freeze + + ############################################# + + if TkCore::WITH_ENCODING ### Ruby 1.9 + RubyEncoding = ::Encoding + + # for saving GC cost + #ENCNAMES_CMD = ['encoding'.freeze, 'names'.freeze] + BINARY_NAME = 'binary'.freeze + UTF8_NAME = 'utf-8'.freeze + DEFAULT_EXTERNAL_NAME = RubyEncoding.default_external.name.freeze + + BINARY = RubyEncoding.find(BINARY_NAME) + UNKNOWN = RubyEncoding.find('ASCII-8BIT') + + ### start of creating ENCODING_TABLE + ENCODING_TABLE = TkCore::INTERP.encoding_table +=begin + ENCODING_TABLE = { + 'binary' => BINARY, + # 'UNKNOWN-8BIT' => UNKNOWN, + } + + list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0], + ENCNAMES_CMD[1]) + TkCore::INTERP._split_tklist(list).each{|name| + begin + enc = RubyEncoding.find(name) + rescue ArgumentError + case name + when 'identity' + enc = BINARY + when 'shiftjis' + enc = RubyEncoding.find('Shift_JIS') + when 'unicode' + enc = RubyEncoding.find('UTF-8') + #if Tk.tk_call('set', 'tcl_platform(byteOrder)') =='littleEndian' + # enc = RubyEncoding.find('UTF-16LE') + #else + # enc = RubyEncoding.find('UTF-16BE') + #end + when 'symbol' + # single byte data + enc = RubyEncoding.find('ASCII-8BIT') ### ??? + else + # unsupported on Ruby, but supported on Tk + enc = TkCore::INTERP.create_dummy_encoding_for_tk(name) + end + end + ENCODING_TABLE[name.freeze] = enc + } +=end +=begin + def ENCODING_TABLE.get_name(enc) + orig_enc = enc + + # unles enc, use system default + # 1st: Ruby/Tk default encoding + # 2nd: Tcl/Tk default encoding + # 3rd: Ruby's default_external + enc ||= TkCore::INTERP.encoding + enc ||= TclTkLib.encoding_system + enc ||= DEFAULT_EXTERNAL_NAME + + if enc.kind_of?(RubyEncoding) + # Ruby's Encoding object + if (name = self.key(enc)) + return name + end + + # Is it new ? + list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0], + ENCNAMES_CMD[1]) + TkComm.simplelist(list).each{|name| + if ((enc == RubyEncoding.find(name)) rescue false) + # new relation!! update table + self[name.freeze] = enc + return name + end + } + else + # String or Symbol ? + if self[name = enc.to_s] + return name + end + + # Is it new ? + if (enc_obj = (RubyEncoding.find(name) rescue false)) + list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0], + ENCNAMES_CMD[1]) + if TkComm.simplelist(list).index(name) + # Tk's encoding name ? + self[name.freeze] = enc_obj # new relation!! update table + return name + else + # Ruby's encoding name ? + if (name = self.key(enc_obj)) + return name + end + end + end + end + + fail ArgumentError, "unsupported Tk encoding '#{orig_enc}'" + end + + def ENCODING_TABLE.get_obj(enc) + # returns the encoding object. + # If 'enc' is the encoding name on Tk only, it returns nil. + ((obj = self[self.get_name(enc)]).kind_of?(RubyEncoding))? obj: nil + end +=end + ### end of creating ENCODING_TABLE + + end + + ############################################# + + if TkCore::WITH_ENCODING + ################################ + ### Ruby 1.9 + ################################ + def force_default_encoding(mode) + TkCore::INTERP.force_default_encoding = mode + end + + def force_default_encoding? + TkCore::INTERP.force_default_encoding? + end + + def default_encoding=(enc) + TkCore::INTERP.default_encoding = Tk::Encoding::ENCODING_TABLE.get_name(enc) + end + + def encoding=(enc) + TkCore::INTERP.encoding = Tk::Encoding::ENCODING_TABLE.get_name(enc) + end + + def encoding_name + Tk::Encoding::ENCODING_TABLE.get_name(TkCore::INTERP.encoding) + end + def encoding_obj + Tk::Encoding::ENCODING_TABLE.get_obj(TkCore::INTERP.encoding) + end + alias encoding encoding_name + alias default_encoding encoding_name + + def tk_encoding_names + TkComm.simplelist(TkCore::INTERP._invoke_without_enc(Tk::Encoding::ENCNAMES_CMD[0], Tk::Encoding::ENCNAMES_CMD[1])) + end + def encoding_names + self.tk_encoding_names.find_all{|name| + Tk::Encoding::ENCODING_TABLE.get_name(name) rescue false + } + end + def encoding_objs + self.tk_encoding_names.map!{|name| + Tk::Encoding::ENCODING_TABLE.get_obj(name) rescue nil + }.compact + end + + def encoding_system=(enc) + TclTkLib.encoding_system = Tk::Encoding::ENCODING_TABLE.get_name(enc) + end + + def encoding_system_name + Tk::Encoding::ENCODING_TABLE.get_name(TclTkLib.encoding_system) + end + def encoding_system_obj + Tk::Encoding::ENCODING_TABLE.get_obj(TclTkLib.encoding_system) + end + alias encoding_system encoding_system_name + + ################################ + else + ################################ + ### Ruby 1.8- + ################################ + def force_default_encoding=(mode) + true + end + + def force_default_encoding? + true + end + + def default_encoding=(enc) + TkCore::INTERP.default_encoding = enc + end + + def encoding=(enc) + TkCore::INTERP.encoding = enc + end + + def encoding_obj + TkCore::INTERP.encoding + end + def encoding_name + TkCore::INTERP.encoding + end + alias encoding encoding_name + alias default_encoding encoding_name + + def tk_encoding_names + TkComm.simplelist(Tk.tk_call('encoding', 'names')) + end + def encoding_objs + self.tk_encoding_names + end + def encoding_names + self.tk_encoding_names + end + + def encoding_system=(enc) + TclTkLib.encoding_system = enc + end + + def encoding_system_name + TclTkLib.encoding_system + end + def encoding_system_obj + TclTkLib.encoding_system + end + alias encoding_system encoding_system_name + + ################################ + end + + def encoding_convertfrom(str, enc=nil) + enc = encoding_system_name unless enc + str = str.dup + if TkCore::WITH_ENCODING + if str.kind_of?(Tk::EncodedString) + str.__instance_variable_set('@encoding', nil) + else + str.instance_variable_set('@encoding', nil) + end + str.force_encoding('binary') + else + str.instance_variable_set('@encoding', 'binary') + end + ret = TkCore::INTERP._invoke_without_enc('encoding', 'convertfrom', + enc, str) + if TkCore::WITH_ENCODING + ret.force_encoding('utf-8') + else + Tk::UTF8_String.new(ret) + end + ret + end + alias encoding_convert_from encoding_convertfrom + + def encoding_convertto(str, enc=nil) + # str must be a UTF-8 string + enc = encoding_system_name unless enc + ret = TkCore::INTERP._invoke_without_enc('encoding', 'convertto', + enc, str) + #ret.instance_variable_set('@encoding', 'binary') + if TkCore::WITH_ENCODING + #ret.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj('binary')) + ret.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj(enc)) + end + ret + end + alias encoding_convert_to encoding_convertto + + def encoding_dirs + # Tcl8.5 feature + TkComm.simplelist(Tk.tk_call_without_enc('encoding', 'dirs')) + end + + def encoding_dirs=(dir_list) # an array or a Tcl's list string + # Tcl8.5 feature + Tk.tk_call_without_enc('encoding', 'dirs', dir_list) + end + end + + extend Encoding + end + class TclTkIp + def force_default_encoding=(mode) + @force_default_encoding = (mode)? true: false + end + + def force_default_encoding? + @force_default_encoding ||= false + end + + def default_encoding=(name) + name = name.name if name.kind_of?(::Encoding) if Tk::WITH_ENCODING + @encoding = name + end + # from tkencoding.rb by ttate@jaist.ac.jp - attr_accessor :encoding + #attr_accessor :encoding + def encoding=(name) + self.force_default_encoding = true # for comaptibility + self.default_encoding = name + end - alias __eval _eval - alias __invoke _invoke + def encoding_name + (@encoding)? @encoding.dup: nil + end + alias encoding encoding_name + alias default_encoding encoding_name + + def encoding_obj + if Tk::WITH_ENCODING + Tk::Encoding.tcl2rb_encoding(@encoding) + else + (@encoding)? @encoding.dup: nil + end + end alias __toUTF8 _toUTF8 alias __fromUTF8 _fromUTF8 + if Object.const_defined?(:Encoding) && ::Encoding.class == Class + # with Encoding (Ruby 1.9+) + # + # use functions on Tcl as default. + # but when unsupported encoding on Tcl, use methods on Ruby. + # + def _toUTF8(str, enc = nil) + if enc + # use given encoding + begin + enc_name = Tk::Encoding::ENCODING_TABLE.get_name(enc) + rescue + # unknown encoding for Tk -> try to convert encoding on Ruby + str = str.dup.force_encoding(enc) + str.encode!(Tk::Encoding::UTF8_NAME) # modify self !! + return str # if no error, probably succeed converting + end + end + + enc_name ||= str.instance_variable_get(:@encoding) + + enc_name ||= + Tk::Encoding::ENCODING_TABLE.get_name(str.encoding) rescue nil + + unless enc_name + # str.encoding isn't supported by Tk -> try to convert on Ruby + begin + return str.encode(Tk::Encoding::UTF8_NAME) # new string + rescue + # error -> ignore, try to use default encoding of Ruby/Tk + end + end + + #enc_name ||= + # Tk::Encoding::ENCODING_TABLE.get_name(Tk.encoding) rescue nil + enc_name ||= Tk::Encoding::ENCODING_TABLE.get_name(nil) + + # is 'binary' encoding? + if enc_name == Tk::Encoding::BINARY_NAME + return str.dup.force_encoding(Tk::Encoding::BINARY_NAME) + end + + # force default encoding? + if ! str.kind_of?(Tk::EncodedString) && self.force_default_encoding? + enc_name = Tk::Encoding::ENCODING_TABLE.get_name(Tk.default_encoding) + end + + encstr = __toUTF8(str, enc_name) + encstr.force_encoding(Tk::Encoding::UTF8_NAME) + encstr + end + def _fromUTF8(str, enc = nil) + # str must be UTF-8 or binary. + enc_name = str.instance_variable_get(:@encoding) + enc_name ||= + Tk::Encoding::ENCODING_TABLE.get_name(str.encoding) rescue nil + + # is 'binary' encoding? + if enc_name == Tk::Encoding::BINARY_NAME + return str.dup.force_encoding(Tk::Encoding::BINARY_NAME) + end + + # get target encoding name (if enc == nil, use default encoding) + begin + enc_name = Tk::Encoding::ENCODING_TABLE.get_name(enc) + rescue + # then, enc != nil + # unknown encoding for Tk -> try to convert encoding on Ruby + str = str.dup.force_encoding(Tk::Encoding::UTF8_NAME) + str.encode!(enc) # modify self !! + return str # if no error, probably succeed converting + end + + encstr = __fromUTF8(str, enc_name) + encstr.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj(enc_name)) + encstr + end + ### + else + # without Encoding (Ruby 1.8) + def _toUTF8(str, encoding = nil) + __toUTF8(str, encoding) + end + def _fromUTF8(str, encoding = nil) + __fromUTF8(str, encoding) + end + ### + end + + alias __eval _eval + alias __invoke _invoke + + def _eval(cmd) + _fromUTF8(__eval(_toUTF8(cmd))) + end + + def _invoke(*cmds) + _fromUTF8(__invoke(*(cmds.collect{|cmd| _toUTF8(cmd)}))) + end + + alias _eval_with_enc _eval + alias _invoke_with_enc _invoke + =begin #### --> definition is moved to TclTkIp module @@ -2330,17 +2780,6 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) end =end - def _eval(cmd) - _fromUTF8(__eval(_toUTF8(cmd))) - end - - def _invoke(*cmds) - _fromUTF8(__invoke(*(cmds.collect{|cmd| _toUTF8(cmd)}))) - end - - alias _eval_with_enc _eval - alias _invoke_with_enc _invoke - =begin def _eval(cmd) if defined?(@encoding) && @encoding != 'utf-8' @@ -2397,81 +2836,43 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) module TclTkLib class << self - alias _encoding encoding - alias _encoding= encoding= - def encoding=(name) - TkCore::INTERP.encoding = name - end - def encoding - TkCore::INTERP.encoding + def force_default_encoding=(mode) + TkCore::INTERP.force_default_encoding = mode end - end - end - module Tk - module Encoding - extend Encoding + def force_default_encoding? + TkCore::INTERP.force_default_encoding? + end - TkCommandNames = ['encoding'.freeze].freeze + def default_encoding=(name) + TkCore::INTERP.default_encoding = name + end + alias _encoding encoding + alias _encoding= encoding= def encoding=(name) + name = name.name if name.kind_of?(::Encoding) if Tk::WITH_ENCODING TkCore::INTERP.encoding = name end - def encoding + def encoding_name TkCore::INTERP.encoding end + alias encoding encoding_name + alias default_encoding encoding_name - def encoding_names - TkComm.simplelist(Tk.tk_call('encoding', 'names')) - end - - def encoding_system - Tk.tk_call('encoding', 'system') - end - - def encoding_system=(enc) - Tk.tk_call('encoding', 'system', enc) - end - - def encoding_convertfrom(str, enc=nil) - # str is an usual enc string or a Tcl's internal string expression - # in enc (which is returned from 'encoding_convertto' method). - # the return value is a UTF-8 string. - enc = encoding_system unless enc - ret = TkCore::INTERP.__invoke('encoding', 'convertfrom', enc, str) - ret.instance_variable_set('@encoding', 'utf-8') - ret - end - alias encoding_convert_from encoding_convertfrom - - def encoding_convertto(str, enc=nil) - # str must be a UTF-8 string. - # The return value is a Tcl's internal string expression in enc. - # To get an usual enc string, use Tk.fromUTF8(ret_val, enc). - enc = encoding_system unless enc - ret = TkCore::INTERP.__invoke('encoding', 'convertto', enc, str) - ret.instance_variable_set('@encoding', 'binary') - ret - end - alias encoding_convert_to encoding_convertto - - def encoding_dirs - # Tcl8.5 feature - TkComm.simplelist(Tk.tk_call_without_enc('encoding', 'dirs')) - end - - def encoding_dirs=(dir_list) # an array or a Tcl's list string - # Tcl8.5 feature - Tk.tk_call_without_enc('encoding', 'dirs', dir_list) + def encoding_obj + if Tk::WITH_ENCODING + Tk::Encoding.tcl2rb_encoding(TkCore::INTERP.encoding) + else + TkCore::INTERP.encoding + end end end - - extend Encoding end # estimate encoding - unless TkCore::WITH_ENCODING ### Ruby 1.9 !!!!!!!!!!!! + unless TkCore::WITH_ENCODING case $KCODE when /^e/i # EUC Tk.encoding = 'euc-jp' @@ -2502,89 +2903,147 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) Tk.encoding_system = 'utf-8' end end - else ######################### - $TK_ENCODING ||= Encoding.default_external.name - case $TK_ENCODING - when 'US_ASCII' - Tk.encoding = 'ascii' - Tk.encoding_system = 'ascii' - when 'BIG5' - Tk.encoding = 'big5' - Tk.encoding_system = 'big5' - when 'CP1251' - Tk.encoding = 'cp1251' - Tk.encoding_system = 'cp1251' - when 'EUC-JP' - Tk.encoding = 'euc-jp' - Tk.encoding_system = 'euc-jp' - when 'EUC-KR' - Tk.encoding = 'euc-kr' - Tk.encoding_system = 'euc-kr' - when 'EUC-TW', 'EUC-CN' - Tk.encoding = 'euc-cn' - Tk.encoding_system = 'euc-cn' - #when 'GB18030' - # Tk.encoding = 'gb12345' # ???????????? - # Tk.encoding_system = 'gb12345' # ???????????? - when 'ISO-2022-JP' - Tk.encoding = 'iso2022-jp' - Tk.encoding_system = 'iso2022-jp' - when /ISO-8859-(.*)/ - Tk.encoding = 'iso8859-' << $1 - Tk.encoding_system = 'iso8859-' << $1 - #when 'KOI8', 'KOI8-U' - # Tk.encoding = 'koi8-u' # ???????????? - # Tk.encoding_system = 'koi8-u' # ???????????? - when 'KOI8-R' - Tk.encoding = 'koi8-r' - Tk.encoding_system = 'koi8-r' - when 'Shift_JIS' - begin - if Tk.encoding_system == 'cp932' - Tk.encoding = 'cp932' + + else ### Ruby 1.9 !!!!!!!!!!!! + loc_enc_obj = ::Encoding.find(::Encoding.locale_charmap) + ext_enc_obj = ::Encoding.default_external + tksys_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(Tk.encoding_system) + # p [Tk.encoding, Tk.encoding_system, loc_enc_obj, ext_enc_obj] + +=begin + if ext_enc_obj == Tk::Encoding::UNKNOWN + if defind? DEFAULT_TK_ENCODING + if DEFAULT_TK_ENCODING.kind_of?(::Encoding) + tk_enc_name = DEFAULT_TK_ENCODING.name + tksys_enc_name = DEFAULT_TK_ENCODING.name else - Tk.encoding = 'shiftjis' - Tk.encoding_system = 'shiftjis' + tk_enc_name = DEFAULT_TK_ENCODING + tksys_enc_name = DEFAULT_TK_ENCODING end - rescue StandardError, NameError - Tk.encoding = 'shiftjis' - Tk.encoding_system = 'shiftjis' + else + tk_enc_name = loc_enc_obj.name + tksys_enc_name = loc_enc_obj.name end - when 'UNICODE' - Tk.encoding = 'unicode' - Tk.encoding_system = 'unicode' - when 'UTF-8' - Tk.encoding = 'utf-8' - Tk.encoding_system = 'utf-8' - else ###### 'ASCII-8BIT' - if defined? DEFAULT_TK_ENCODING - Tk.encoding_system = DEFAULT_TK_ENCODING + else + tk_enc_name = ext_enc_obj.name + tksys_enc_name = ext_enc_obj.name + end + + # Tk.encoding = tk_enc_name + Tk.default_encoding = tk_enc_name + Tk.encoding_system = tksys_enc_name +=end + + if ext_enc_obj == Tk::Encoding::UNKNOWN + if loc_enc_obj == Tk::Encoding::UNKNOWN + # use Tk.encoding_system + else + # use locale_charmap + begin + loc_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(loc_enc_obj) + if loc_enc_name && loc_enc_name != tksys_enc_name + # use locale_charmap + Tk.encoding_system = loc_enc_name + else + # use Tk.encoding_system + end + rescue ArgumentError + # unsupported encoding on Tk -> use Tk.encoding_system + end end + else begin - Tk.encoding = Tk.encoding_system - rescue StandardError, NameError - Tk.encoding = 'utf-8' - Tk.encoding_system = 'utf-8' + ext_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(ext_enc_obj) + if ext_enc_name && ext_enc_name != tksys_enc_name + # use default_external + Tk.encoding_system = ext_enc_name + else + # use Tk.encoding_system + end + rescue ArgumentError + # unsupported encoding on Tk -> use Tk.encoding_system end end - end -else - # dummy methods - class TclTkIp - attr_accessor :encoding + # setup Tk.encoding + enc_name = nil - alias __eval _eval - alias __invoke _invoke + begin + default_def = DEFAULT_TK_ENCODING + if ::Encoding.find(default_def.to_s) != Tk::Encoding::UNKNOWN + enc_name = Tk::Encoding::ENCODING_TABLE.get_name(default_def) + end + rescue NameError + # ignore + enc_name = nil + rescue ArgumentError + enc_name = nil + fail ArgumentError, + "DEFAULT_TK_ENCODING has an unknown encoding #{default_def}" + end - alias _eval_with_enc _eval - alias _invoke_with_enc _invoke + unless enc_name + if ext_enc_obj == Tk::Encoding::UNKNOWN + if loc_enc_obj == Tk::Encoding::UNKNOWN + # use Tk.encoding_system + enc_name = tksys_enc_name + else + # use locale_charmap + begin + loc_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(loc_enc_obj) + if loc_enc_name && loc_enc_name != tksys_enc_name + # use locale_charmap + enc_name = loc_enc_name + else + # use Tk.encoding_system + enc_name = tksys_enc_name + end + rescue ArgumentError + # unsupported encoding on Tk -> use Tk.encoding_system + enc_name = tksys_enc_name + end + end + else + begin + ext_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(ext_enc_obj) + if ext_enc_name && ext_enc_name != tksys_enc_name + # use default_external + enc_name = ext_enc_name + else + # use Tk.encoding_system + enc_name = tksys_enc_name + end + rescue ArgumentError + # unsupported encoding on Tk -> use Tk.encoding_system + enc_name = tksys_enc_name + end + end + end + + Tk.default_encoding = (enc_name)? enc_name: tksys_enc_name end +else + # dummy methods module Tk module Encoding extend Encoding + def force_default_encoding=(mode) + nil + end + + def force_default_encoding? + nil + end + + def default_encoding=(enc) + nil + end + def default_encoding + nil + end + def encoding=(name) nil end @@ -2620,6 +3079,16 @@ else extend Encoding end + + class TclTkIp + attr_accessor :encoding + + alias __eval _eval + alias __invoke _invoke + + alias _eval_with_enc _eval + alias _invoke_with_enc _invoke + end end @@ -2949,6 +3418,14 @@ module TkConfigMethod include TkUtil include TkTreatFont + def TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + @mode || false + end + def TkConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) + fail SecurityError, "can't change the mode" if $SAFE>=4 + @mode = (mode)? true: false + end + def __cget_cmd [self.path, 'cget'] end @@ -3076,7 +3553,7 @@ module TkConfigMethod val end - def cget(slot) + def __cget_core(slot) orig_slot = slot slot = slot.to_s @@ -3152,8 +3629,17 @@ module TkConfigMethod tk_tcl2ruby(tk_call_without_enc(*(__cget_cmd << "-#{slot}")), true) end end + private :__cget_core - def configure(slot, value=None) + def cget(slot) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + __cget_core(slot) + else + __cget_core(slot) rescue nil + end + end + + def __configure_core(slot, value=None) if slot.kind_of? Hash slot = _symbolkey2str(slot) @@ -3216,12 +3702,45 @@ module TkConfigMethod end self end + private :__configure_core + + def __check_available_configure_options(keys) + availables = self.current_configinfo.keys + + # add non-standard keys + availables |= __font_optkeys.map{|k| + [k.to_s, "latin#{k}", "ascii#{k}", "kanji#{k}"] + }.flatten + availables |= __methodcall_optkeys.keys.map{|k| k.to_s} + availables |= __keyonly_optkeys.keys.map{|k| k.to_s} + + keys = _symbolkey2str(keys) + keys.delete_if{|k, v| !(availables.include?(k))} + end + + def configure(slot, value=None) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + __configure_core(slot, value) + else + if slot.kind_of?(Hash) + begin + __configure_core(slot) + rescue + slot = __check_available_configure_options(slot) + __configure_core(slot) unless slot.empty? + end + else + __configure_core(slot, value) rescue nil + end + end + self + end def configure_cmd(slot, value) configure(slot, install_cmd(value)) end - def configinfo(slot = nil) + def __configinfo_core(slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/) @@ -3232,6 +3751,10 @@ module TkConfigMethod conf[__configinfo_struct[:key]][1..-1] if ( ! __configinfo_struct[:alias] \ || conf.size > __configinfo_struct[:alias] + 1 ) + fnt = conf[__configinfo_struct[:default_value]] + if TkFont.is_system_font?(fnt) + conf[__configinfo_struct[:default_value]] = TkNamedFont.new(fnt) + end conf[__configinfo_struct[:current_value]] = fontobj(fontkey) elsif ( __configinfo_struct[:alias] \ && conf.size == __configinfo_struct[:alias] + 1 \ @@ -3568,6 +4091,11 @@ module TkConfigMethod fontconf = ret.assoc(optkey) if fontconf && fontconf.size > 2 ret.delete_if{|inf| inf[0] =~ /^(|latin|ascii|kanji)#{optkey}$/} + fnt = fontconf[__configinfo_struct[:default_value]] + if TkFont.is_system_font?(fnt) + fontconf[__configinfo_struct[:default_value]] \ + = TkNamedFont.new(fnt) + end fontconf[__configinfo_struct[:current_value]] = fontobj(optkey) ret.push(fontconf) end @@ -3592,6 +4120,10 @@ module TkConfigMethod if ( ! __configinfo_struct[:alias] \ || conf.size > __configinfo_struct[:alias] + 1 ) + fnt = conf[__configinfo_struct[:default_value]] + if TkFont.is_system_font?(fnt) + conf[__configinfo_struct[:default_value]] = TkNamedFont.new(fnt) + end conf[__configinfo_struct[:current_value]] = fontobj(fontkey) { conf.shift => conf } elsif ( __configinfo_struct[:alias] \ @@ -3939,6 +4471,11 @@ module TkConfigMethod ret.delete('latin' << optkey) ret.delete('ascii' << optkey) ret.delete('kanji' << optkey) + fnt = fontconf[__configinfo_struct[:default_value]] + if TkFont.is_system_font?(fnt) + fontconf[__configinfo_struct[:default_value]] \ + = TkNamedFont.new(fnt) + end fontconf[__configinfo_struct[:current_value]] = fontobj(optkey) ret[optkey] = fontconf end @@ -3953,6 +4490,19 @@ module TkConfigMethod end end end + private :__configinfo_core + + def configinfo(slot = nil) + if slot && TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + begin + __configinfo_core(slot) + rescue + Array.new(__configinfo_struct.values.max).unshift(slot.to_s) + end + else + __configinfo_core(slot) + end + end def current_configinfo(slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY @@ -4052,7 +4602,12 @@ class TkObject<TkKernel begin cget(name) rescue - super(id, *args) + if self.kind_of?(TkWindow) + fail NameError, + "unknown option '#{id}' for #{self.inspect} (deleted widget?)" + else + super(id, *args) + end # fail NameError, # "undefined local variable or method `#{name}' for #{self.to_s}", # error_at @@ -4107,6 +4662,7 @@ end class TkWindow<TkObject include TkWinfo extend TkBindCore + include Tk::Wm_for_General @@WIDGET_INSPECT_FULL = false def TkWindow._widget_inspect_full_? @@ -4210,7 +4766,20 @@ class TkWindow<TkObject end if keys and keys != None - tk_call_without_enc(cmd, @path, *hash_kv(keys, true)) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + tk_call_without_enc(cmd, @path, *hash_kv(keys, true)) + else + begin + tk_call_without_enc(cmd, @path, *hash_kv(keys, true)) + rescue + tk_call_without_enc(cmd, @path) + keys = __check_available_configure_options(keys) + unless keys.empty? + tk_call_without_enc('destroy', @path) + tk_call_without_enc(cmd, @path, *hash_kv(keys, true)) + end + end + end else tk_call_without_enc(cmd, @path) end @@ -4748,7 +5317,7 @@ TkWidget = TkWindow #Tk.freeze module Tk - RELEASE_DATE = '2008-02-29'.freeze + RELEASE_DATE = '2008-03-29'.freeze autoload :AUTO_PATH, 'tk/variable' autoload :TCL_PACKAGE_PATH, 'tk/variable' diff --git a/ext/tk/lib/tk/autoload.rb b/ext/tk/lib/tk/autoload.rb index f7037b403..0773f7708 100644 --- a/ext/tk/lib/tk/autoload.rb +++ b/ext/tk/lib/tk/autoload.rb @@ -93,6 +93,7 @@ module Tk autoload :Scrollable, 'tk/scrollable' autoload :Wm, 'tk/wm' + autoload :Wm_for_General, 'tk/wm' autoload :MacResource, 'tk/macpkg' @@ -159,7 +160,7 @@ autoload :TkWarningObj, 'tk/dialog' autoload :TkEvent, 'tk/event' autoload :TkFont, 'tk/font' -autoload :TkTreatTagFont, 'tk/font' +autoload :TkNamedFont, 'tk/font' autoload :TkImage, 'tk/image' autoload :TkBitmapImage, 'tk/image' @@ -314,11 +315,16 @@ module Tk :TkWinRegistry => 'tk/winpkg', } + @TOPLEVEL_ALIAS_OWNER = {} + @TOPLEVEL_ALIAS_SETUP_PROC = {} @current_default_widget_set = nil end + +############################################ +# methods to control default widget set ############################################ class << Tk @@ -341,7 +347,8 @@ class << Tk @TOPLEVEL_ALIAS_TABLE[target = target.to_sym] ||= {} symbols.each{|sym| @TOPLEVEL_ALIAS_TABLE[target][sym = sym.to_sym] = obj - if @current_default_widget_set == target + # if @current_default_widget_set == target + if @TOPLEVEL_ALIAS_OWNER[sym] == target Object.class_eval{remove_const sym} if Object.const_defined?(sym) Object.const_set(sym, obj) end @@ -372,6 +379,7 @@ class << Tk # file => loaded class object Object.const_set(sym, file) end + @TOPLEVEL_ALIAS_OWNER[sym] = target } # update current alias @@ -386,10 +394,11 @@ Tk.default_widget_set = :Tk ############################################ # depend on the version of Tcl/Tk -major, minor, type, type_name, patchlevel = TclTkLib.get_version +# major, minor, type, type_name, patchlevel = TclTkLib.get_version ############################################ # Ttk (Tile) support +=begin if major > 8 || (major == 8 && minor > 5) || (major == 8 && minor == 5 && type >= TclTkLib::RELEASE_TYPE::BETA) @@ -399,3 +408,7 @@ if major > 8 || require 'tk/ttk_selector' end +=end +Object.autoload :Ttk, 'tkextlib/tile' +Tk.autoload :Tile, 'tkextlib/tile' +require 'tk/ttk_selector' diff --git a/ext/tk/lib/tk/bindtag.rb b/ext/tk/lib/tk/bindtag.rb index 9023a08e0..88c8367a8 100644 --- a/ext/tk/lib/tk/bindtag.rb +++ b/ext/tk/lib/tk/bindtag.rb @@ -8,30 +8,64 @@ class TkBindTag #BTagID_TBL = {} BTagID_TBL = TkCore::INTERP.create_table - Tk_BINDTAG_ID = ["btag".freeze, "00000".taint].freeze - TkCore::INTERP.init_ip_env{ BTagID_TBL.clear } + (Tk_BINDTAG_ID = ["btag".freeze, "00000".taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + BTagID_TBL.mutex.synchronize{ BTagID_TBL.clear } + } def TkBindTag.id2obj(id) - BTagID_TBL[id]? BTagID_TBL[id]: id + BTagID_TBL.mutex.synchronize{ + (BTagID_TBL[id])? BTagID_TBL[id]: id + } end +=begin def TkBindTag.new_by_name(name, *args, &b) - return BTagID_TBL[name] if BTagID_TBL[name] + BTagID_TBL.mutex.synchronize{ + return BTagID_TBL[name] if BTagID_TBL[name] + } + self.new.instance_eval{ - BTagID_TBL.delete @id - @id = name - BTagID_TBL[@id] = self + BTagID_TBL.mutex.synchronize{ + BTagID_TBL.delete @id + @id = name + BTagID_TBL[@id] = self + } bind(*args, &b) if args != [] self } end +=end + def TkBindTag.new_by_name(name, *args, &b) + obj = nil + BTagID_TBL.mutex.synchronize{ + if BTagID_TBL[name] + obj = BTagID_TBL[name] + else + (obj = BTagID_TBL[name] = self.allocate).instance_eval{ + @id = name + } + end + } + bind(*args, &b) if obj && args != [] + obj + end def initialize(*args, &b) - # @id = Tk_BINDTAG_ID.join('') - @id = Tk_BINDTAG_ID.join(TkCore::INTERP._ip_id_) - Tk_BINDTAG_ID[1].succ! - BTagID_TBL[@id] = self + Tk_BINDTAG_ID.mutex.synchronize{ + # @id = Tk_BINDTAG_ID.join('') + @id = Tk_BINDTAG_ID.join(TkCore::INTERP._ip_id_) + Tk_BINDTAG_ID[1].succ! + } + BTagID_TBL.mutex.synchronize{ + BTagID_TBL[@id] = self + } bind(*args, &b) if args != [] end @@ -63,14 +97,37 @@ end class TkDatabaseClass<TkBindTag +=begin def self.new(name, *args, &b) - return BTagID_TBL[name] if BTagID_TBL[name] + BTagID_TBL.mutex.synchronize{ + return BTagID_TBL[name] if BTagID_TBL[name] + } super(name, *args, &b) end def initialize(name, *args, &b) @id = name - BTagID_TBL[@id] = self + BTagID_TBL.mutex.synchronize{ + BTagID_TBL[@id] = self + } + bind(*args, &b) if args != [] + end +=end + def self.new(name, *args, &b) + BTagID_TBL.mutex.synchronize{ + if BTagID_TBL[name] + BTagID_TBL[name] + else + BTagID_TBL[name] = self.allocate.instance_eval{ + initialize(name, *args, &b) + self + } + end + } + end + + def initialize(name, *args, &b) + @id = name bind(*args, &b) if args != [] end diff --git a/ext/tk/lib/tk/canvas.rb b/ext/tk/lib/tk/canvas.rb index 4abc99202..fceadd5e9 100644 --- a/ext/tk/lib/tk/canvas.rb +++ b/ext/tk/lib/tk/canvas.rb @@ -185,11 +185,17 @@ class Tk::Canvas<TkWindow end def delete(*args) - if TkcItem::CItemID_TBL[self.path] + tbl = nil + TkcItem::CItemID_TBL.mutex.synchronize{ + tbl = TkcItem::CItemID_TBL[self.path] + } + if tbl args.each{|tag| find('withtag', tag).each{|item| if item.kind_of?(TkcItem) - TkcItem::CItemID_TBL[self.path].delete(item.id) + TkcItem::CItemID_TBL.mutex.synchronize{ + tbl.delete(item.id) + } end } } @@ -584,9 +590,12 @@ class TkcItem<TkObject CItemTypeName = nil CItemTypeToClass = {} + CItemID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ CItemID_TBL.clear } + TkCore::INTERP.init_ip_env{ + CItemID_TBL.mutex.synchronize{ CItemID_TBL.clear } + } def TkcItem.type2class(type) CItemTypeToClass[type] @@ -594,8 +603,13 @@ class TkcItem<TkObject def TkcItem.id2obj(canvas, id) cpath = canvas.path - return id unless CItemID_TBL[cpath] - CItemID_TBL[cpath][id]? CItemID_TBL[cpath][id]: id + CItemID_TBL.mutex.synchronize{ + if CItemID_TBL[cpath] + CItemID_TBL[cpath][id]? CItemID_TBL[cpath][id]: id + else + id + end + } end ######################################## @@ -668,8 +682,10 @@ class TkcItem<TkObject @path = parent.path @id = create_self(*args) # an integer number as 'canvas item id' - CItemID_TBL[@path] = {} unless CItemID_TBL[@path] - CItemID_TBL[@path][@id] = self + CItemID_TBL.mutex.synchronize{ + CItemID_TBL[@path] = {} unless CItemID_TBL[@path] + CItemID_TBL[@path][@id] = self + } end def create_self(*args) self.class.create(@c, *args) # return an integer number as 'canvas item id' @@ -690,7 +706,9 @@ class TkcItem<TkObject def delete @c.delete @id - CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + CItemID_TBL.mutex.synchronize{ + CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + } self end alias remove delete diff --git a/ext/tk/lib/tk/canvastag.rb b/ext/tk/lib/tk/canvastag.rb index a5650ee68..7feea1575 100644 --- a/ext/tk/lib/tk/canvastag.rb +++ b/ext/tk/lib/tk/canvastag.rb @@ -199,14 +199,26 @@ class TkcTag<TkObject include TkcTagAccess CTagID_TBL = TkCore::INTERP.create_table - Tk_CanvasTag_ID = ['ctag'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ CTagID_TBL.clear } + (Tk_CanvasTag_ID = ['ctag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + CTagID_TBL.mutex.synchronize{ CTagID_TBL.clear } + } def TkcTag.id2obj(canvas, id) cpath = canvas.path - return id unless CTagID_TBL[cpath] - CTagID_TBL[cpath][id]? CTagID_TBL[cpath][id]: id + CTagID_TBL.mutex.synchronize{ + if CTagID_TBL[cpath] + CTagID_TBL[cpath][id]? CTagID_TBL[cpath][id]: id + else + id + end + } end def initialize(parent, mode=nil, *args) @@ -215,11 +227,15 @@ class TkcTag<TkObject #end @c = parent @cpath = parent.path - # @path = @id = Tk_CanvasTag_ID.join('') - @path = @id = Tk_CanvasTag_ID.join(TkCore::INTERP._ip_id_) - CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] - CTagID_TBL[@cpath][@id] = self - Tk_CanvasTag_ID[1].succ! + Tk_CanvasTag_ID.mutex.synchronize{ + # @path = @id = Tk_CanvasTag_ID.join('') + @path = @id = Tk_CanvasTag_ID.join(TkCore::INTERP._ip_id_) + Tk_CanvasTag_ID[1].succ! + } + CTagID_TBL.mutex.synchronize{ + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + } if mode tk_call_without_enc(@c.path, "addtag", @id, mode, *args) end @@ -238,7 +254,9 @@ class TkcTag<TkObject def delete @c.delete @id - CTagID_TBL[@cpath].delete(@id) if CTagID_TBL[@cpath] + CTagID_TBL.mutex.synchronize{ + CTagID_TBL[@cpath].delete(@id) if CTagID_TBL[@cpath] + } self end alias remove delete @@ -288,23 +306,38 @@ class TkcTag<TkObject end class TkcTagString<TkcTag - def self.new(parent, name, *args) - if CTagID_TBL[parent.path] && CTagID_TBL[parent.path][name] - return CTagID_TBL[parent.path][name] - else - super(parent, name, *args) + def self.new(parent, name, mode=nil, *args) + obj = nil + CTagID_TBL.mutex.synchronize{ + if CTagID_TBL[parent.path] && CTagID_TBL[parent.path][name] + obj = CTagID_TBL[parent.path][name] + else + # super(parent, name, *args) + (obj = self.allocate).instance_eval{ + @c = parent + @cpath = parent.path + @path = @id = name + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + } + end + } + if obj && mode + tk_call_without_enc(@c.path, "addtag", @id, mode, *args) end + obj end def initialize(parent, name, mode=nil, *args) + # dummy:: not called by 'new' method + #unless parent.kind_of?(TkCanvas) # fail ArgumentError, "expect TkCanvas for 1st argument" #end @c = parent @cpath = parent.path @path = @id = name - CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] - CTagID_TBL[@cpath][@id] = self + if mode tk_call_without_enc(@c.path, "addtag", @id, mode, *args) end @@ -312,7 +345,11 @@ class TkcTagString<TkcTag end TkcNamedTag = TkcTagString -class TkcTagAll<TkcTag +class TkcTagAll<TkcTagString + def self.new(parent) + super(parent, 'all') + end +=begin def initialize(parent) #unless parent.kind_of?(TkCanvas) # fail ArgumentError, "expect TkCanvas for 1st argument" @@ -320,12 +357,19 @@ class TkcTagAll<TkcTag @c = parent @cpath = parent.path @path = @id = 'all' - CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] - CTagID_TBL[@cpath][@id] = self + CTagID_TBL.mutex.synchronize{ + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + } end +=end end -class TkcTagCurrent<TkcTag +class TkcTagCurrent<TkcTagString + def self.new(parent) + super(parent, 'current') + end +=begin def initialize(parent) #unless parent.kind_of?(TkCanvas) # fail ArgumentError, "expect TkCanvas for 1st argument" @@ -333,13 +377,21 @@ class TkcTagCurrent<TkcTag @c = parent @cpath = parent.path @path = @id = 'current' - CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] - CTagID_TBL[@cpath][@id] = self + CTagID_TBL.mutex.synchronize{ + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + } end +=end end class TkcGroup<TkcTag - Tk_cGroup_ID = ['tkcg'.freeze, '00000'.taint].freeze + (Tk_cGroup_ID = ['tkcg'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + #def create_self(parent, *args) def initialize(parent, *args) #unless parent.kind_of?(TkCanvas) @@ -347,11 +399,15 @@ class TkcGroup<TkcTag #end @c = parent @cpath = parent.path - # @path = @id = Tk_cGroup_ID.join('') - @path = @id = Tk_cGroup_ID.join(TkCore::INTERP._ip_id_) - CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] - CTagID_TBL[@cpath][@id] = self - Tk_cGroup_ID[1].succ! + Tk_cGroup_ID.mutex.synchronize{ + # @path = @id = Tk_cGroup_ID.join('') + @path = @id = Tk_cGroup_ID.join(TkCore::INTERP._ip_id_) + Tk_cGroup_ID[1].succ! + } + CTagID_TBL.mutex.synchronize{ + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + } include(*args) if args != [] end #private :create_self diff --git a/ext/tk/lib/tk/encodedstr.rb b/ext/tk/lib/tk/encodedstr.rb index 797e514a4..02de0b0d8 100644 --- a/ext/tk/lib/tk/encodedstr.rb +++ b/ext/tk/lib/tk/encodedstr.rb @@ -70,13 +70,89 @@ module Tk # @encoding = ( enc || # ((self.class::Encoding)? # self.class::Encoding : Tk.encoding_system) ) - @encoding = ( enc || - ((self.class::Encoding)? + enc ||= (self.class::Encoding)? self.class::Encoding : - ((Tk.encoding)? Tk.encoding : Tk.encoding_system) ) ) + ((Tk.encoding)? Tk.encoding : Tk.encoding_system) + if TkCore::WITH_ENCODING + unless encobj = Tk::Encoding::ENCODING_TABLE.get_obj(enc) + fail ArgumentError, "unsupported Tk encoding '#{enc}'" + end + self.force_encoding(encobj) + else + @encoding = enc + end + end + + if TkCore::WITH_ENCODING + alias encoding_obj encoding + alias __encoding encoding + def encoding + Tk::Encoding::ENCODING_TABLE.get_name(super()) + end + else + def encoding + @encoding + end + alias encoding_obj encoding end - attr_reader :encoding + if TkCore::WITH_ENCODING + # wrapper methods for compatibility + alias __instance_variable_get instance_variable_get + alias __instance_variable_set instance_variable_set + alias __instance_eval instance_eval + alias __instance_variables instance_variables + + def instance_variable_get(key) + if (key.to_s == '@encoding') + self.encoding + else + super(key) + end + end + + def instance_variable_set(key, value) + if (key.to_s == '@encoding') + if value + self.force_encoding(value) + else + self.force_encoding(Tk::Encoding::UNKNOWN) + end + value + else + super(key, value) + end + end + + def instance_eval(*args, &b) + old_enc = @encoding = self.encoding + + ret = super(*args, &b) + + if @encoding + if @encoding != old_enc + # modified by user + self.force_encoding(@encoding) + end + remove_instance_variable(:@encoding) + else + begin + remove_instance_variable(:@encoding) + # user sets to nil -> use current default + self.force_encoding(Tk.encoding) + rescue NameError + # removed by user -> ignore, because user don't use @encoding + end + end + ret + end + end + + def instance_variables + ret = super() + ret << :@encoding # fake !! + ret + end end # def Tk.EncodedString(str, enc = nil) # Tk::EncodedString.new(str, enc) diff --git a/ext/tk/lib/tk/event.rb b/ext/tk/lib/tk/event.rb index 9884ca02e..0042fcaa6 100644 --- a/ext/tk/lib/tk/event.rb +++ b/ext/tk/lib/tk/event.rb @@ -15,8 +15,6 @@ require 'tk' module TkEvent class Event < TkUtil::CallbackSubst module Grp - major, minor, type, type_name, patchlevel = TclTkLib.get_version - KEY = 0x1 BUTTON = 0x2 MOTION = 0x4 @@ -43,6 +41,8 @@ module TkEvent MWHEEL = KEY + STRING_DATA = 0x80000000 # special flag for 'data' field + ALL = 0xFFFFFFFF KEY_BUTTON_MOTION_VIRTUAL = (KEY|MWHEEL|BUTTON|MOTION|VIRTUAL) @@ -157,7 +157,7 @@ module TkEvent 'borderwidth' => (Grp::CREATE|Grp::CONFIG), 'button' => Grp::BUTTON, 'count' => Grp::EXPOSE, - 'data' => Grp::VIRTUAL, + 'data' => (Grp::VIRTUAL|Grp::STRING_DATA), 'delta' => Grp::MWHEEL, 'detail' => (Grp::FOCUS|Grp::CROSSING), 'focus' => Grp::CROSSING, @@ -225,7 +225,8 @@ module TkEvent rescue next end - next if !val || val == '??' + # next if !val || val == '??' + next if !val || (val == '??' && (flag & Grp::STRING_DATA)) fields[key] = val } @@ -370,6 +371,22 @@ module TkEvent nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + # setup tables to be used by scan_args, _get_subst_key, _get_all_subst_keys # # _get_subst_key() and _get_all_subst_keys() generates key-string diff --git a/ext/tk/lib/tk/font.rb b/ext/tk/lib/tk/font.rb index 444118e6a..4641d8a64 100644 --- a/ext/tk/lib/tk/font.rb +++ b/ext/tk/lib/tk/font.rb @@ -11,13 +11,18 @@ class TkFont TkCommandNames = ['font'.freeze].freeze - Tk_FontID = ["@font".freeze, "00000".taint].freeze + (Tk_FontID = ["@font".freeze, "00000".taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + Tk_FontNameTBL = TkCore::INTERP.create_table Tk_FontUseTBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ - Tk_FontNameTBL.clear - Tk_FontUseTBL.clear + Tk_FontNameTBL.mutex.synchronize{ Tk_FontNameTBL.clear } + Tk_FontUseTBL.mutex.synchronize{ Tk_FontUseTBL.clear } } # option_type : default => string @@ -31,13 +36,26 @@ class TkFont MetricType = Hash.new(?n) MetricType['fixed'] = ?b + # system font names + SYSTEM_FONT_NAMES = [] + def SYSTEM_FONT_NAMES.add(font_names) + (@mutex ||= Mutex.new).synchronize{ + self.replace(self | font_names.map{|name| name.to_s}) + } + end + def SYSTEM_FONT_NAMES.include?(name) + (@mutex ||= Mutex.new).synchronize{ + super(name.to_s) + } + end + # set default font case Tk::TK_VERSION - when /^4\.*/ + when /^4\..*/ DEFAULT_LATIN_FONT_NAME = 'a14'.freeze DEFAULT_KANJI_FONT_NAME = 'k14'.freeze - when /^8\.*/ + when /^8\.[0-4]/ if JAPANIZED_TK begin fontnames = tk_call('font', 'names') @@ -103,6 +121,15 @@ class TkFont DEFAULT_LATIN_FONT_NAME = ltn.freeze DEFAULT_KANJI_FONT_NAME = knj.freeze + when /^8\.[5-9]/, /^9\..*/ + if tk_call('font', 'names') =~ /\bTkDefaultFont\b/ + DEFAULT_LATIN_FONT_NAME = 'TkDefaultFont'.freeze + DEFAULT_KANJI_FONT_NAME = 'TkDefaultFont'.freeze + else + DEFAULT_LATIN_FONT_NAME = 'Helvetica'.freeze + DEFAULT_KANJI_FONT_NAME = 'mincho'.freeze + end + else # unknown version DEFAULT_LATIN_FONT_NAME = 'Helvetica'.freeze DEFAULT_KANJI_FONT_NAME = 'mincho'.freeze @@ -121,6 +148,7 @@ class TkFont unless compound.kind_of?(TkFont) fail ArgumentError, "a TkFont object is expected for the 1st argument" end + @compound = compound case type when 'kanji', 'latin', 'ascii' @@ -145,6 +173,9 @@ class TkFont def font @compound.__send__(@type + '_font_id') end + alias font_id font + alias name font + alias to_s font def [](slot) @compound.__send__(@type + '_configinfo', slot) @@ -163,6 +194,14 @@ class TkFont ################################### # class methods ################################### + def TkFont.is_system_font?(fnt) + # true --> system font which is available on the current system + # false --> not system font (or unknown system font) + # nil --> system font name, but not available on the current system + fnt = fnt.to_s + SYSTEM_FONT_NAMES.include?(fnt) && self.names.index(fnt) && true + end + def TkFont.actual(fnt, option=nil) fnt = '{}' if fnt == '' if fnt.kind_of?(TkFont) @@ -171,6 +210,9 @@ class TkFont actual_core(fnt, nil, option) end end + def TkFont.actual_hash(fnt, option=nil) + Hash[TkFont.actual_hash(fnt, option)] + end def TkFont.actual_displayof(fnt, win, option=nil) fnt = '{}' if fnt == '' @@ -181,6 +223,9 @@ class TkFont actual_core(fnt, win, option) end end + def TkFont.actual_hash_displayof(fnt, option=nil) + Hash[TkFont.actual_hash_displayof(fnt, option)] + end def TkFont.configure(fnt, slot, value=None) if fnt.kind_of?(TkFont) @@ -234,6 +279,33 @@ class TkFont metrics_core(fnt, nil, option) end end + def TkFont.metrics_hash(fnt, option=nil) + if option + val = TkFont.metrics(fnt, option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[TkFont.metrics(fnt)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h + end def TkFont.metrics_displayof(fnt, win, option=nil) fnt = '{}' if fnt == '' @@ -244,13 +316,40 @@ class TkFont metrics_core(fnt, win, option) end end + def TkFont.metrics_hash_displayof(fnt, win, option=nil) + if option + val = TkFont.metrics_displayof(fnt, win, option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[TkFont.metrics_displayof(fnt, win, option)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h + end def TkFont.families(win=nil) case (Tk::TK_VERSION) - when /^4\.*/ + when /^4\..*/ ['fixed'] - when /^8\.*/ + when /^8\..*/ if win tk_split_simplelist(tk_call('font', 'families', '-displayof', win)) else @@ -261,13 +360,16 @@ class TkFont def TkFont.names case (Tk::TK_VERSION) - when /^4\.*/ + when /^4\..*/ r = ['fixed'] r += ['a14', 'k14'] if JAPANIZED_TK - Tk_FontNameTBL.each_value{|obj| r.push(obj)} - r | [] + Tk_FontNameTBL.mutex.synchronize{ + Tk_FontNameTBL.each_value{|obj| r.push(obj)} + } + #r | [] + r.uniq - when /^8\.*/ + when /^8\..*/ tk_split_simplelist(tk_call('font', 'names')) end @@ -285,10 +387,15 @@ class TkFont end def TkFont.get_obj(name) + name = name.to_s if name =~ /^(@font[0-9]+)(|c|l|k)$/ - Tk_FontNameTBL[$1] + Tk_FontNameTBL.mutex.synchronize{ + Tk_FontNameTBL[$1] + } else - nil + Tk_FontNameTBL.mutex.synchronize{ + Tk_FontNameTBL[name] + } end end @@ -298,7 +405,7 @@ class TkFont path = [win, tag, key].join(';') case (Tk::TK_VERSION) - when /^4\.*/ + when /^4\..*/ regexp = /^-(|kanji)#{key} / conf_list = tk_split_simplelist(tk_call(*args)). @@ -324,7 +431,7 @@ class TkFont TkFont.new(ltn, knj).call_font_configure([path, key], *args) - when /^8\.*/ + when /^8\.[0-4]/ regexp = /^-#{key} / conf_list = tk_split_simplelist(tk_call(*args)). @@ -360,26 +467,66 @@ class TkFont compound = [] end if compound == [] - TkFont.new(fnt).call_font_configure([path, key], *args) + if TkFont.is_system_font?(fnt) + TkNamedFont.new(fnt).call_font_configure([path, key], *args) + else + TkFont.new(fnt).call_font_configure([path, key], *args) + end else TkFont.new(compound[0], compound[1]).call_font_configure([path, key], *args) end end + + when /^8\.[5-9]/, /^9\..*/ + regexp = /^-#{key} / + + conf_list = tk_split_simplelist(tk_call(*args)). + find_all{|prop| prop =~ regexp}. + collect{|prop| tk_split_simplelist(prop)} + + if conf_list.size == 0 + raise RuntimeError, "the widget may not support 'font' option" + end + + args << {} + + optkey = "-#{key}" + + info = conf_list.find{|conf| conf[0] == optkey} + fnt = info[-1] + fnt = nil if fnt == [] || fnt == "" + + unless fnt + # create dummy + # TkFont.new(nil, nil).call_font_configure([path, key], *args) + dummy_fnt = TkFont.allocate + dummy_fnt.instance_eval{ init_dummy_fontobj() } + dummy_fnt + else + if TkFont.is_system_font?(fnt) + TkNamedFont.new(fnt).call_font_configure([path, key], *args) + else + TkFont.new(fnt).call_font_configure([path, key], *args) + end + end end end def TkFont.used_on(path=nil) - if path - Tk_FontUseTBL[path] - else - Tk_FontUseTBL.values | [] - end + Tk_FontUseTBL.mutex.synchronize{ + if path + Tk_FontUseTBL[path] + else + # Tk_FontUseTBL.values | [] + Tk_FontUseTBL.values.uniq + end + } end def TkFont.failsafe(font) begin - if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK + if /^8\..*/ === Tk::TK_VERSION && JAPANIZED_TK tk_call('font', 'failsafe', font) end rescue @@ -392,15 +539,20 @@ class TkFont private ################################### def init_dummy_fontobj - @id = Tk_FontID.join(TkCore::INTERP._ip_id_) - Tk_FontID[1].succ! - Tk_FontNameTBL[@id] = self + Tk_FontID.mutex.synchronize{ + @id = Tk_FontID.join(TkCore::INTERP._ip_id_) + Tk_FontID[1].succ! + } + Tk_FontNameTBL.mutex.synchronize{ + Tk_FontNameTBL[@id] = self + } - @latin_desscendant = nil - @kanji_desscendant = nil + # @latin_desscendant = nil + # @kanji_desscendant = nil + @descendant = [nil, nil] # [latin, kanji] case (Tk::TK_VERSION) - when /^4\.*/ + when /^4\..*/ @latinfont = "" @kanjifont = "" if JAPANIZED_TK @@ -436,13 +588,23 @@ class TkFont ltn = '{}' if ltn == '' knj = '{}' if knj == '' - # @id = Tk_FontID.join('') - @id = Tk_FontID.join(TkCore::INTERP._ip_id_) - Tk_FontID[1].succ! - Tk_FontNameTBL[@id] = self + Tk_FontID.mutex.synchronize{ + # @id = Tk_FontID.join('') + @id = Tk_FontID.join(TkCore::INTERP._ip_id_) + Tk_FontID[1].succ! + } + Tk_FontNameTBL.mutex.synchronize{ + Tk_FontNameTBL[@id] = self + } + + # @latin_desscendant = nil + # @kanji_desscendant = nil + @descendant = [nil, nil] # [latin, kanji] - @latin_desscendant = nil - @kanji_desscendant = nil + # @latinfont = @id + 'l' + # @kanjifont = @id + 'k' + # @compoundfont = @id + 'c' + # @fontslot = {} if knj.kind_of?(Hash) && !keys keys = knj @@ -474,7 +636,7 @@ class TkFont if ltn if JAPANIZED_TK && !knj - if Tk::TK_VERSION =~ /^4.*/ + if Tk::TK_VERSION =~ /^4..*/ knj = DEFAULT_KANJI_FONT_NAME else knj = ltn @@ -625,9 +787,14 @@ class TkFont if JAPANIZED_TK @compoundfont = [[@latinfont], [@kanjifont]] @fontslot = {'font'=>@latinfont, 'kanjifont'=>@kanjifont} + # @fontslot.clear + # @fontslot['font'] = @latinfont + # @fontslot['kanjifont'] = @kanjifont else @compoundfont = @latinfont @fontslot = {'font'=>@latinfont} + # @fontslot.clear + # @fontslot['font'] = @latinfont end end @@ -753,6 +920,7 @@ class TkFont end @fontslot = {'font'=>@compoundfont} + # @fontslot['font'] = @compoundfont begin tk_call('font', 'create', @compoundfont, '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) @@ -833,6 +1001,7 @@ class TkFont end @fontslot = {'font'=>@compoundfont} + # @fontslot['font'] = @compoundfont tk_call('font', 'configure', @compoundfont, *hash_kv(keys)) end end @@ -888,13 +1057,19 @@ class TkFont keys = _symbolkey2str(args.pop).update(fontslot) args.concat(hash_kv(keys)) tk_call(*args) - Tk_FontUseTBL[[win, tag, optkey].join(';')] = self + Tk_FontUseTBL.mutex.synchronize{ + Tk_FontUseTBL[[win, tag, optkey].join(';')] = self + } self end def used ret = [] - Tk_FontUseTBL.each{|key,value| + table = nil + Tk_FontUseTBL.mutex.synchronize{ + table = Tk_FontUseTBL.clone # to avoid deadlock + } + table.each{|key,value| next unless self == value if key.include?(';') win, tag, optkey = key.split(';') @@ -960,6 +1135,8 @@ class TkFont @compoundfont end alias font_id font + alias name font + alias to_s font def latin_font_id @latinfont @@ -967,11 +1144,18 @@ class TkFont def latin_font # @latinfont + if @descendant[0] # [0] -> latin + @descendant[0] + else + @descendant[0] = DescendantFont.new(self, 'latin') + end +=begin if @latin_descendant @latin_descendant else @latin_descendant = DescendantFont.new(self, 'latin') end +=end end alias latinfont latin_font @@ -981,50 +1165,87 @@ class TkFont def kanji_font # @kanjifont + if @descendant[1] # [1] -> kanji + @descendant[1] + else + @descendant[1] = DescendantFont.new(self, 'kanji') + end +=begin if @kanji_descendant @kanji_descendant else @kanji_descendant = DescendantFont.new(self, 'kanji') end +=end end alias kanjifont kanji_font def actual(option=nil) actual_core(@compoundfont, nil, option) end + def actual_hash(option=nil) + Hash[actual(option)] + end def actual_displayof(win, option=nil) win = '.' unless win actual_core(@compoundfont, win, option) end + def actual_hash_displayof(win, option=nil) + Hash[actual_displayof(win, option)] + end def latin_actual(option=nil) - actual_core(@latinfont, nil, option) + if @latinfont == nil + actual_core(@compoundfont, nil, option) # use @compoundfont + else + actual_core(@latinfont, nil, option) + end + end + def latin_actual_hash(option=nil) + Hash[latin_actual(option)] end def latin_actual_displayof(win, option=nil) win = '.' unless win - actual_core(@latinfont, win, option) + if @latinfont == nil + actual_core(@compoundfont, win, option) # use @compoundfont + else + actual_core(@latinfont, win, option) + end + end + def latin_actual_hash_displayof(win, option=nil) + Hash[latin_actual_displayof(win, option)] end def kanji_actual(option=nil) #if JAPANIZED_TK - if @kanjifont != "" + if @kanjifont == nil + actual_core(@compoundfont, nil, option) # use @compoundfont + elsif @kanjifont != "" actual_core(@kanjifont, nil, option) else actual_core_tk4x(nil, nil, option) end end + def kanji_actual_hash(option=nil) + Hash[kanji_actual(option)] + end def kanji_actual_displayof(win, option=nil) #if JAPANIZED_TK - if @kanjifont != "" + if @kanjifont == nil + actual_core(@compoundfont, nil, option) # use @compoundfont + elsif @kanjifont != "" win = '.' unless win actual_core(@kanjifont, win, option) else actual_core_tk4x(nil, win, option) end end + def kanji_actual_hash_displayof(win, option=nil) + Hash[kanji_actual_displayof(win, option)] + end def [](slot) configinfo slot @@ -1068,10 +1289,15 @@ class TkFont configinfo(slot) end end + def latin_current_configinfo(slot=nil) + Hash[latin_configinfo(slot)] + end def kanji_configure(slot, value=None) #if JAPANIZED_TK - if @kanjifont != "" + if @kanjifont == nil + configure_core(@compoundfont, slot, value) # use @compoundfont + elsif @kanjifont != "" configure_core(@kanjifont, slot, value) configure('size'=>configinfo('size')) # to reflect new configuration else @@ -1083,13 +1309,18 @@ class TkFont def kanji_configinfo(slot=nil) #if JAPANIZED_TK - if @kanjifont != "" + if @kanjifont == nil + configure_core(@compoundfont, slot) # use @compoundfont + elsif @kanjifont != "" configinfo_core(@kanjifont, slot) else #[] configinfo(slot) end end + def kanji_current_configinfo(slot=nil) + Hash[kanji_configinfo(slot)] + end def replace(ltn, knj=None) knj = ltn if knj == None @@ -1099,12 +1330,30 @@ class TkFont end def latin_replace(ltn) - latin_replace_core(ltn) - reset_pointadjust + if @latinfont + latin_replace_core(ltn) + reset_pointadjust + else + # not compound font -> copy properties of ltn + latinkeys = {} + begin + actual_core(ltn).each{|key,val| latinkeys[key] = val} + rescue + latinkeys = {} + end + begin + tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys)) + rescue + # not exist? (deleted?) -> create font + tk_call('font', 'create', @compoundfont, *hash_kv(latinkeys)) + end + end + self end def kanji_replace(knj) + return self unless @kanjifont # ignore kanji_replace_core(knj) reset_pointadjust self @@ -1122,41 +1371,215 @@ class TkFont def metrics(option=nil) metrics_core(@compoundfont, nil, option) end + def metrics_hash(option=nil) + if option + val = metrics(option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[metrics(option)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h + end def metrics_displayof(win, option=nil) win = '.' unless win metrics_core(@compoundfont, win, option) end + def metrics_hash_displayof(win, option=nil) + if option + val = metrics_displayof(win, option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[metrics_displayof(win, option)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h + end def latin_metrics(option=nil) - metrics_core(@latinfont, nil, option) + if @latinfont == nil + metrics_core(@compoundfont, nil, option) # use @compoundfont + else + metrics_core(@latinfont, nil, option) + end + end + def latin_metrics_hash(option=nil) + if option + val = latin_metrics(option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[latin_metrics(option)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h end def latin_metrics_displayof(win, option=nil) win = '.' unless win - metrics_core(@latinfont, win, option) + if @latinfont == nil + metrics_core(@compoundfont, win, option) # use @compoundfont + else + metrics_core(@latinfont, win, option) + end + end + def latin_metrics_hash_displayof(win, option=nil) + if option + val = latin_metrics_displayof(win, option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[latin_metrics_displayof(win, option)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h end def kanji_metrics(option=nil) - if JAPANIZED_TK + if @latinfont == nil + metrics_core(@compoundfont, nil, option) # use @compoundfont + elsif JAPANIZED_TK metrics_core(@kanjifont, nil, option) else metrics_core_tk4x(nil, nil, option) end end + def kanji_metrics_hash(option=nil) + if option + val = kanji_metrics(option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[kanji_metrics(option)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h + end def kanji_metrics_displayof(win, option=nil) - if JAPANIZED_TK - win = '.' unless win + win = '.' unless win + if @latinfont == nil + metrics_core(@compoundfont, win, option) # use @compoundfont + elsif JAPANIZED_TK metrics_core(@kanjifont, win, option) else metrics_core_tk4x(nil, win, option) end end + def kanji_metrics_hash_displayof(win, option=nil) + if option + val = kanji_metrics_displayof(win, option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[kanji_metrics_displayof(win, option)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h + end def reset_pointadjust begin - if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK + if /^8\..*/ === Tk::TK_VERSION && JAPANIZED_TK configure('pointadjust' => latin_actual.assoc('size')[1].to_f / kanji_actual.assoc('size')[1].to_f ) end @@ -1169,7 +1592,7 @@ class TkFont # private alias ################################### case (Tk::TK_VERSION) - when /^4\.*/ + when /^4\..*/ alias create_latinfont create_latinfont_tk4x alias create_kanjifont create_kanjifont_tk4x alias create_compoundfont create_compoundfont_tk4x @@ -1474,32 +1897,44 @@ module TkFont::CoreMethods end def delete_core_tk4x - TkFont::Tk_FontNameTBL.delete(@id) - TkFont::Tk_FontUseTBL.delete_if{|key,value| value == self} + TkFont::Tk_FontNameTBL.mutex.synchronize{ + TkFont::Tk_FontNameTBL.delete(@id) + } + TkFont::Tk_FontUseTBL.mutex.synchronize{ + TkFont::Tk_FontUseTBL.delete_if{|key,value| value == self} + } end def delete_core_tk8x begin - tk_call('font', 'delete', @latinfont) + tk_call('font', 'delete', @latinfont) if @latinfont rescue end begin - tk_call('font', 'delete', @kanjifont) + tk_call('font', 'delete', @kanjifont) if @kanjifont rescue end begin - tk_call('font', 'delete', @compoundfont) + tk_call('font', 'delete', @compoundfont) if @compoundfont rescue end - TkFont::Tk_FontNameTBL.delete(@id) - TkFont::Tk_FontUseTBL.delete_if{|key,value| value == self} + TkFont::Tk_FontNameTBL.mutex.synchronize{ + TkFont::Tk_FontNameTBL.delete(@id) + } + TkFont::Tk_FontUseTBL.mutex.synchronize{ + TkFont::Tk_FontUseTBL.delete_if{|key,value| value == self} + } end def latin_replace_core_tk4x(ltn) create_latinfont_tk4x(ltn) @compoundfont[0] = [@latinfont] if JAPANIZED_TK @fontslot['font'] = @latinfont - TkFont::Tk_FontUseTBL.dup.each{|w, fobj| + table = nil + TkFont::Tk_FontUseTBL.mutex.synchronize{ + table = TkFont::Tk_FontUseTBL.clone + } + table.each{|w, fobj| if self == fobj begin if w.include?(';') @@ -1524,7 +1959,9 @@ module TkFont::CoreMethods tk_call(w, 'configure', '-font', @latinfont) end rescue - TkFont::Tk_FontUseTBL.delete(w) + TkFont::Tk_FontUseTBL.mutex.synchronize{ + TkFont::Tk_FontUseTBL.delete(w) + } end end } @@ -1537,7 +1974,11 @@ module TkFont::CoreMethods create_kanjifont_tk4x(knj) @compoundfont[1] = [@kanjifont] @fontslot['kanjifont'] = @kanjifont - TkFont::Tk_FontUseTBL.dup.each{|w, fobj| + table = nil + TkFont::Tk_FontUseTBL.mutex.synchronize{ + table = TkFont::Tk_FontUseTBL.clone + } + table.dup.each{|w, fobj| if self == fobj begin if w.include?(';') @@ -1562,7 +2003,9 @@ module TkFont::CoreMethods tk_call(w, 'configure', '-kanjifont', @kanjifont) end rescue - TkFont::Tk_FontUseTBL.delete(w) + Tk_FontUseTBL.mutex.synchronize{ + TkFont::Tk_FontUseTBL.delete(w) + } end end } @@ -1627,8 +2070,11 @@ module TkFont::CoreMethods rescue latinkeys = {} end - if latinkeys != {} + begin tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys)) + rescue + # not exist? (deleted?) -> create font + tk_call('font', 'create', @compoundfont, *hash_kv(latinkeys)) end end self @@ -1720,6 +2166,13 @@ module TkFont::CoreMethods r = [] while key=l.shift r.push [key[1..-1], l.shift.to_i] +=begin + if key == '-fixed' # boolean value + r.push [key[1..-1], bool(l.shift)] + else + r.push [key[1..-1], l.shift.to_i] + end +=end end r end @@ -1729,7 +2182,7 @@ module TkFont::CoreMethods # private alias ################################### case (Tk::TK_VERSION) - when /^4\.*/ + when /^4\..*/ alias actual_core actual_core_tk4x alias configure_core configure_core_tk4x alias configinfo_core configinfo_core_tk4x @@ -1769,3 +2222,117 @@ class TkFont include TkFont::CoreMethods extend TkFont::CoreMethods end + +class TkNamedFont < TkFont + # for built-in named fonts + def TkNamedFont.find(name) + name = name.to_s + unless (obj = Tk_FontNameTBL[name]) + obj = self.new(name) if TkFont.is_system_font?(name) + end + obj + end + + def TkNamedFont.new(name, keys=nil) + name = name.to_s + obj = nil + Tk_FontNameTBL.mutex.synchronize{ + unless (obj = Tk_FontNameTBL[name]) + (obj = self.allocate).instance_eval{ + @id = @compoundfont = name.to_s + @latinfont = nil + @kanjifont = nil + @descendant = [self, self] # [latin, kanji] : dummy + Tk_FontNameTBL[@id] = self + } + end + } + obj.instance_eval{ initialize(name, keys) } + obj + end + + ########################### + private + ########################### + def initialize(name, keys=nil) + @id = @compoundfont = name.to_s + + # if not exist named font, create it. + begin + if keys + tk_call('font', 'configure', @compoundfont, keys) + else + tk_call('font', 'configure', @compoundfont) + end + rescue + # the named font doesn't exist -> create + if keys + tk_call('font', 'create', @compoundfont, keys) + else + tk_call('font', 'create', @compoundfont) + end + end + end + + def create_latinfont(fnt) + # ignore + end + def create_kanjifont(fnt) + # ignore + end + def create_compoundfont(ltn, knj, keys) + # ignore + end + + ########################### + public + ########################### + def latin_font_id + @compoundfont + end + def kanji_font_id + @compoundfont + end +end + +####################################### +# define system font names +####################################### +if Tk::TCL_MAJOR_VERSION > 8 || + (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5) + # add standard fonts of Tcl/Tk 8.5+ + TkFont::SYSTEM_FONT_NAMES.add [ + 'TkDefaultFont', 'TkTextFont', 'TkFixedFont', 'TkMenuFont', + 'TkHeadingFont', 'TkCaptionFont', 'TkSmallCaptionFont', + 'TkIconFont', 'TkTooltipFont' + ] +end + +# platform-specific fonts +# -- windows +TkFont::SYSTEM_FONT_NAMES.add [ + 'ansifixed', 'ansi', 'device', 'oemfixed', 'systemfixed', 'system' +] + +# -- macintosh, macosx +TkFont::SYSTEM_FONT_NAMES.add ['system', 'application'] + +if Tk::TCL_MAJOR_VERSION > 8 || + (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5) + TkFont::SYSTEM_FONT_NAMES.add ['menu'] +end + +# -- macosx (Aqua theme) +if Tk::TCL_MAJOR_VERSION > 8 || + (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5) + TkFont::SYSTEM_FONT_NAMES.add [ + 'systemSystemFont', 'systemEmphasizedSystemFont', + 'systemSmallSystemFont', 'systemSmallEmphasizedSystemFont', + 'systemApplicationFont', 'systemLabelFont', 'systemViewsFont', + 'systemMenuTitleFont', 'systemMenuItemFont', 'systemMenuItemMarkFont', + 'systemMenuItemCmdKeyFont', 'systemWindowTitleFont', + 'systemPushButtonFont', 'systemUtilityWindowTitleFont', + 'systemAlertHeaderFont', 'systemToolbarFont', 'systemMiniSystemFont', + 'systemDetailSystemFont', 'systemDetailEmphasizedSystemFont' + ] +end diff --git a/ext/tk/lib/tk/image.rb b/ext/tk/lib/tk/image.rb index 35e2c4e39..57f82cb81 100644 --- a/ext/tk/lib/tk/image.rb +++ b/ext/tk/lib/tk/image.rb @@ -10,9 +10,16 @@ class TkImage<TkObject TkCommandNames = ['image'.freeze].freeze Tk_IMGTBL = TkCore::INTERP.create_table - Tk_Image_ID = ['i'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ Tk_IMGTBL.clear } + (Tk_Image_ID = ['i'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + Tk_IMGTBL.mutex.synchronize{ Tk_IMGTBL.clear } + } def self.new(keys=nil) if keys.kind_of?(Hash) @@ -27,7 +34,10 @@ class TkImage<TkObject obj = name else name = _get_eval_string(name) - obj = Tk_IMGTBL[name] + obj = nil + Tk_IMGTBL.mutex.synchronize{ + obj = Tk_IMGTBL[name] + } end if obj if !(keys[:without_creating] || keys['without_creating']) @@ -43,7 +53,13 @@ class TkImage<TkObject end end end - super(keys) + (obj = self.allocate).instance_eval{ + Tk_IMGTBL.mutex.synchronize{ + initialize(keys) + Tk_IMGTBL[@path] = self + } + } + obj end def initialize(keys=nil) @@ -55,19 +71,22 @@ class TkImage<TkObject without_creating = keys.delete('without_creating') end unless @path - # @path = Tk_Image_ID.join('') - @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_) - Tk_Image_ID[1].succ! + Tk_Image_ID.mutex.synchronize{ + # @path = Tk_Image_ID.join('') + @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_) + Tk_Image_ID[1].succ! + } end unless without_creating tk_call_without_enc('image', 'create', @type, @path, *hash_kv(keys, true)) end - Tk_IMGTBL[@path] = self end def delete - Tk_IMGTBL.delete(@id) if @id + Tk_IMGTBL.mutex.synchronize{ + Tk_IMGTBL.delete(@id) if @id + } tk_call_without_enc('image', 'delete', @path) self end @@ -85,8 +104,10 @@ class TkImage<TkObject end def TkImage.names - Tk.tk_call_without_enc('image', 'names').split.collect!{|id| - (Tk_IMGTBL[id])? Tk_IMGTBL[id] : id + Tk_IMGTBL.mutex.synchronize{ + Tk.tk_call_without_enc('image', 'names').split.collect!{|id| + (Tk_IMGTBL[id])? Tk_IMGTBL[id] : id + } } end diff --git a/ext/tk/lib/tk/itemconfig.rb b/ext/tk/lib/tk/itemconfig.rb index a7885e74f..dbc45a9e7 100644 --- a/ext/tk/lib/tk/itemconfig.rb +++ b/ext/tk/lib/tk/itemconfig.rb @@ -115,6 +115,14 @@ module TkItemConfigMethod include TkTreatItemFont include TkItemConfigOptkeys + def TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + @mode || false + end + def TkItemConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) + fail SecurityError, "can't change the mode" if $SAFE>=4 + @mode = (mode)? true: false + end + def __item_cget_cmd(id) # maybe need to override [self.path, 'itemcget', id] @@ -149,7 +157,7 @@ module TkItemConfigMethod ################################################ - def itemcget(tagOrId, option) + def __itemcget_core(tagOrId, option) orig_opt = option option = option.to_s @@ -224,8 +232,27 @@ module TkItemConfigMethod tk_tcl2ruby(tk_call_without_enc(*(__item_cget_cmd(tagid(tagOrId)) << "-#{option}")), true) end end + private :__itemcget_core - def itemconfigure(tagOrId, slot, value=None) + def itemcget(tagOrId, option) + unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + __itemcget_core(tagOrId, option) + else + begin + __itemcget_core(tagOrId, option) + rescue => e + begin + __itemconfiginfo_core(tagOrId) + # not tag error -> option is unknown + nil + rescue + fail e # tag error + end + end + end + end + + def __itemconfigure_core(tagOrId, slot, value=None) if slot.kind_of? Hash slot = _symbolkey2str(slot) @@ -288,6 +315,48 @@ module TkItemConfigMethod end self end + private :__itemconfigure_core + + def __check_available_itemconfigure_options(tagOrId, keys) + id = tagid(tagOrId) + availables = self.current_itemconfiginfo(id).keys + + # add non-standard keys + availables |= __font_optkeys.map{|k| + [k.to_s, "latin#{k}", "ascii#{k}", "kanji#{k}"] + }.flatten + availables |= __item_methodcall_optkeys(id).keys.map{|k| k.to_s} + availables |= __item_keyonly_optkeys(id).keys.map{|k| k.to_s} + + keys = _symbolkey2str(keys) + keys.delete_if{|k, v| !(availables.include?(k))} + end + + def itemconfigure(tagOrId, slot, value=None) + unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + __itemconfigure_core(tagOrId, slot, value) + else + if slot.kind_of?(Hash) + begin + __itemconfigure_core(tagOrId, slot) + rescue + slot = __check_available_configure_options(tagOrId, slot) + __itemconfigure_core(tagOrId, slot) unless slot.empty? + end + else + begin + __itemconfigure_core(tagOrId, slot, value) + rescue => e + begin + __itemconfiginfo_core(tagOrId) + rescue + fail e # tag error + end + end + end + end + self + end def __itemconfiginfo_core(tagOrId, slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY @@ -299,6 +368,10 @@ module TkItemConfigMethod conf[__item_configinfo_struct(tagid(tagOrId))[:key]][1..-1] if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \ || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) + fnt = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] + if TkFont.is_system_font?(fnt) + conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt) + end conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), fontkey) elsif ( __item_configinfo_struct(tagid(tagOrId))[:alias] \ && conf.size == __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 \ @@ -635,6 +708,10 @@ module TkItemConfigMethod fontconf = ret.assoc(optkey) if fontconf && fontconf.size > 2 ret.delete_if{|inf| inf[0] =~ /^(|latin|ascii|kanji)#{optkey}$/} + fnt = fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] + if TkFont.is_system_font?(fnt) + fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt) + end fontconf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), optkey) ret.push(fontconf) end @@ -658,7 +735,11 @@ module TkItemConfigMethod if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \ || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) - conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = fontobj(tagid(tagOrId), fontkey) + fnt = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] + if TkFont.is_system_font?(fnt) + conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt) + end + conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), fontkey) { conf.shift => conf } elsif ( __item_configinfo_struct(tagid(tagOrId))[:alias] \ && conf.size == __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) @@ -1006,6 +1087,10 @@ module TkItemConfigMethod ret.delete('latin' << optkey) ret.delete('ascii' << optkey) ret.delete('kanji' << optkey) + fnt = fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] + if TkFont.is_system_font?(fnt) + fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt) + end fontconf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), optkey) ret[optkey] = fontconf end @@ -1023,7 +1108,21 @@ module TkItemConfigMethod private :__itemconfiginfo_core def itemconfiginfo(tagOrId, slot = nil) - __itemconfiginfo_core(tagOrId, slot) + if slot && TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + begin + __itemconfiginfo_core(tagOrId, slot) + rescue => e + begin + __itemconfiginfo_core(tagOrId) + # not tag error -> option is unknown + Array.new(__item_configinfo_struct.values.max).unshift(slot.to_s) + rescue + fail e # tag error + end + end + else + __itemconfiginfo_core(tagOrId, slot) + end end def current_itemconfiginfo(tagOrId, slot = nil) diff --git a/ext/tk/lib/tk/menu.rb b/ext/tk/lib/tk/menu.rb index e44f0e3ff..8ba315629 100644 --- a/ext/tk/lib/tk/menu.rb +++ b/ext/tk/lib/tk/menu.rb @@ -202,6 +202,9 @@ class Tk::Menu<TkWindow tk_send_without_enc('unpost') self end + def xposition(index) + number(tk_send_without_enc('xposition', _get_eval_enc_str(index))) + end def yposition(index) number(tk_send_without_enc('yposition', _get_eval_enc_str(index))) end @@ -503,9 +506,24 @@ class Tk::Menubutton<Tk::Label WidgetClassNames[WidgetClassName] = self def create_self(keys) if keys and keys != None - # tk_call_without_enc('menubutton', @path, *hash_kv(keys, true)) - tk_call_without_enc(self.class::TkCommandNames[0], @path, - *hash_kv(keys, true)) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + # tk_call_without_enc('menubutton', @path, *hash_kv(keys, true)) + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + else + begin + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + rescue + tk_call_without_enc(self.class::TkCommandNames[0], @path) + keys = __check_available_configure_options(keys) + unless keys.empty? + tk_call_without_enc('destroy', @path) + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + end + end + end else # tk_call_without_enc('menubutton', @path) tk_call_without_enc(self.class::TkCommandNames[0], @path) @@ -612,6 +630,9 @@ class Tk::OptionMenubutton<Tk::Menubutton @menu.delete(index, last) self end + def xposition(index) + @menu.xposition(index) + end def yposition(index) @menu.yposition(index) end diff --git a/ext/tk/lib/tk/msgcat.rb b/ext/tk/lib/tk/msgcat.rb index 061e43fd8..162953f42 100644 --- a/ext/tk/lib/tk/msgcat.rb +++ b/ext/tk/lib/tk/msgcat.rb @@ -74,7 +74,11 @@ class TkMsgCatalog < TkObject "\n---< backtrace of Ruby side >-----\n" + _toUTF8(e.backtrace.join("\n")) + "\n---< backtrace of Tk side >-------" - msg.instance_variable_set(:@encoding, 'utf-8') + if TkCore::WITH_ENCODING + msg.force_encoding('utf-8') + else + msg.instance_variable_set(:@encoding, 'utf-8') + end rescue Exception msg = e.class.inspect + ': ' + e.message + "\n" + "\n---< backtrace of Ruby side >-----\n" + diff --git a/ext/tk/lib/tk/namespace.rb b/ext/tk/lib/tk/namespace.rb index 5bf6474c5..9d2213ff5 100644 --- a/ext/tk/lib/tk/namespace.rb +++ b/ext/tk/lib/tk/namespace.rb @@ -12,17 +12,24 @@ class TkNamespace < TkObject ].freeze Tk_Namespace_ID_TBL = TkCore::INTERP.create_table - Tk_Namespace_ID = ["ns".freeze, "00000".taint].freeze + + (Tk_Namespace_ID = ["ns".freeze, "00000".taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } Tk_NsCode_RetObjID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ - Tk_Namespace_ID_TBL.clear - Tk_NsCode_RetObjID_TBL.clear + Tk_Namespace_ID_TBL.mutex.synchronize{ Tk_Namespace_ID_TBL.clear } + Tk_NsCode_RetObjID_TBL.mutex.synchronize{ Tk_NsCode_RetObjID_TBL.clear } } def TkNamespace.id2obj(id) - Tk_Namespace_ID_TBL[id]? Tk_Namespace_ID_TBL[id]: id + Tk_Namespace_ID_TBL.mutex.synchronize{ + Tk_Namespace_ID_TBL[id]? Tk_Namespace_ID_TBL[id]: id + } end ##################################### @@ -65,11 +72,13 @@ class TkNamespace < TkObject def cget(slot) if slot == :namespace || slot == 'namespace' ns = super(slot) - if TkNamespace::Tk_Namespace_ID_TBL.key?(ns) - TkNamespace::Tk_Namespace_ID_TBL[ns] - else - ns - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + if TkNamespace::Tk_Namespace_ID_TBL.key?(ns) + TkNamespace::Tk_Namespace_ID_TBL[ns] + else + ns + end + } else super(slot) end @@ -79,9 +88,11 @@ class TkNamespace < TkObject if slot if slot == :namespace || slot == 'namespace' val = super(slot) - if TkNamespace::Tk_Namespace_ID_TBL.key?(val) - val = TkNamespace::Tk_Namespace_ID_TBL[val] - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + if TkNamespace::Tk_Namespace_ID_TBL.key?(val) + val = TkNamespace::Tk_Namespace_ID_TBL[val] + end + } else val = super(slot) end @@ -96,19 +107,23 @@ class TkNamespace < TkObject info = super() if TkComm::GET_CONFIGINFO_AS_ARRAY - info.map!{|inf| - if inf[0] == 'namespace' && - TkNamespace::Tk_Namespace_ID_TBL.key?(inf[-1]) - [inf[0], TkNamespace::Tk_Namespace_ID_TBL[inf[-1]]] - else - inf - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + info.map!{|inf| + if inf[0] == 'namespace' && + TkNamespace::Tk_Namespace_ID_TBL.key?(inf[-1]) + [inf[0], TkNamespace::Tk_Namespace_ID_TBL[inf[-1]]] + else + inf + end + } } else # ! TkComm::GET_CONFIGINFO_AS_ARRAY val = info['namespace'] - if TkNamespace::Tk_Namespace_ID_TBL.key?(val) - info['namespace'] = TkNamespace::Tk_Namespace_ID_TBL[val] - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + if TkNamespace::Tk_Namespace_ID_TBL.key?(val) + info['namespace'] = TkNamespace::Tk_Namespace_ID_TBL[val] + end + } end info @@ -215,9 +230,11 @@ class TkNamespace < TkObject def initialize(name = nil, parent = nil) unless name - # name = Tk_Namespace_ID.join('') - name = Tk_Namespace_ID.join(TkCore::INTERP._ip_id_) - Tk_Namespace_ID[1].succ! + Tk_Namespace_ID.mutex.synchronize{ + # name = Tk_Namespace_ID.join('') + name = Tk_Namespace_ID.join(TkCore::INTERP._ip_id_) + Tk_Namespace_ID[1].succ! + } end name = __tk_call('namespace', 'current') if name == '' if parent @@ -252,7 +269,9 @@ class TkNamespace < TkObject # create namespace __tk_call('namespace', 'eval', @fullname, '') - Tk_Namespace_ID_TBL[@fullname] = self + Tk_Namespace_ID_TBL.mutex.synchronize{ + Tk_Namespace_ID_TBL[@fullname] = self + } end def self.children(*args) @@ -260,11 +279,13 @@ class TkNamespace < TkObject # <pattern> must be glob-style pattern tk_split_simplelist(tk_call('namespace', 'children', *args)).collect{|ns| # ns is fullname - if Tk_Namespace_ID_TBL.key?(ns) - Tk_Namespace_ID_TBL[ns] - else - ns - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + if Tk_Namespace_ID_TBL.key?(ns) + Tk_Namespace_ID_TBL[ns] + else + ns + end + } } end def children(pattern=None) @@ -290,14 +311,24 @@ class TkNamespace < TkObject def code(script = Proc.new) if script.kind_of?(String) cmd = proc{|*args| - ret = ScopeArgs.new(@fullname,*args).instance_eval(script) + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + obj = ScopeArgs.new(@fullname,*args) + ret = obj.instance_exec(obj, script) + else + ret = ScopeArgs.new(@fullname,*args).instance_eval(script) + end id = ret.object_id TkNamespace::Tk_NsCode_RetObjID_TBL[id] = ret id } elsif script.kind_of?(Proc) cmd = proc{|*args| - ret = ScopeArgs.new(@fullname,*args).instance_eval(&script) + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + obj = ScopeArgs.new(@fullname,*args) + ret = obj.instance_exec(obj, &script) + else + ret = ScopeArgs.new(@fullname,*args).instance_eval(&script) + end id = ret.object_id TkNamespace::Tk_NsCode_RetObjID_TBL[id] = ret id @@ -319,11 +350,13 @@ class TkNamespace < TkObject def self.current ns = self.current_path - if Tk_Namespace_ID_TBL.key?(ns) - Tk_Namespace_ID_TBL[ns] - else - ns - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + if Tk_Namespace_ID_TBL.key?(ns) + Tk_Namespace_ID_TBL[ns] + else + ns + end + } end def current_namespace # ns_tk_call('namespace', 'current') @@ -335,11 +368,13 @@ class TkNamespace < TkObject def self.delete(*ns_list) tk_call('namespace', 'delete', *ns_list) ns_list.each{|ns| - if ns.kind_of?(TkNamespace) - Tk_Namespace_ID_TBL.delete(ns.path) - else - Tk_Namespace_ID_TBL.delete(ns.to_s) - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + if ns.kind_of?(TkNamespace) + Tk_Namespace_ID_TBL.delete(ns.path) + else + Tk_Namespace_ID_TBL.delete(ns.to_s) + end + } } end def delete @@ -371,7 +406,7 @@ class TkNamespace < TkObject def self.eval(namespace, cmd = Proc.new, *args) #tk_call('namespace', 'eval', namespace, cmd, *args) - TkNamespace.new(namespece).eval(cmd, *args) + TkNamespace.new(namespace).eval(cmd, *args) end =begin def eval(cmd = Proc.new, *args) @@ -444,11 +479,13 @@ class TkNamespace < TkObject def self.parent(namespace=None) ns = tk_call('namespace', 'parent', namespace) - if Tk_Namespace_ID_TBL.key?(ns) - Tk_Namespace_ID_TBL[ns] - else - ns - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + if Tk_Namespace_ID_TBL.key?(ns) + Tk_Namespace_ID_TBL[ns] + else + ns + end + } end def parent tk_call('namespace', 'parent', @fullname) diff --git a/ext/tk/lib/tk/optiondb.rb b/ext/tk/lib/tk/optiondb.rb index 6a7708ac5..186811d37 100644 --- a/ext/tk/lib/tk/optiondb.rb +++ b/ext/tk/lib/tk/optiondb.rb @@ -8,7 +8,11 @@ module TkOptionDB extend Tk TkCommandNames = ['option'.freeze].freeze - CmdClassID = ['CMD_CLASS'.freeze, '00000'.taint].freeze + (CmdClassID = ['CMD_CLASS'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } module Priority WidgetDefault = 20 @@ -250,8 +254,10 @@ module TkOptionDB def __create_new_class(klass, func, safe = 4, add = false, parent = nil) if klass.kind_of?(TkWindow) carrier = klass.path - klass = CmdClassID.join(TkCore::INTERP._ip_id_) - CmdClassID[1].succ! + CmdClassID.mutex.synchronize{ + klass = CmdClassID.join(TkCore::INTERP._ip_id_) + CmdClassID[1].succ! + } parent = nil # ignore parent else klass = klass.to_s if klass.kind_of?(Symbol) @@ -312,7 +318,7 @@ module TkOptionDB :singleton_methods, :remove_const, :remove_method, :undef_method, :to_s, :inspect, :display, :method, :methods, :respond_to?, :instance_variable_get, :instance_variable_set, :instance_method, - :instance_eval, :instance_variables, :kind_of?, :is_a?, + :instance_eval, :instance_exec, :instance_variables, :kind_of?, :is_a?, :private_methods, :protected_methods, :public_methods ].each{|m| alias_method(m, :__null_method) } diff --git a/ext/tk/lib/tk/root.rb b/ext/tk/lib/tk/root.rb index 4d8328244..7237b4c61 100644 --- a/ext/tk/lib/tk/root.rb +++ b/ext/tk/lib/tk/root.rb @@ -41,7 +41,13 @@ class Tk::Root<TkWindow } end - root.instance_eval(&b) if block_given? + if block_given? + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + root.instance_exec(root, &b) + else + root.instance_eval(&b) + end + end root end diff --git a/ext/tk/lib/tk/scale.rb b/ext/tk/lib/tk/scale.rb index b97ed6807..bf2791ec5 100644 --- a/ext/tk/lib/tk/scale.rb +++ b/ext/tk/lib/tk/scale.rb @@ -14,9 +14,24 @@ class Tk::Scale<TkWindow cmd = keys.delete('command') keys['command'] = proc{|val| cmd.call(val.to_f)} end - #tk_call_without_enc('scale', @path, *hash_kv(keys, true)) - tk_call_without_enc(self.class::TkCommandNames[0], @path, - *hash_kv(keys, true)) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + #tk_call_without_enc('scale', @path, *hash_kv(keys, true)) + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + else + begin + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + rescue + tk_call_without_enc(self.class::TkCommandNames[0], @path) + keys = __check_available_configure_options(keys) + unless keys.empty? + tk_call_without_enc('destroy', @path) + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + end + end + end else #tk_call_without_enc('scale', @path) tk_call_without_enc(self.class::TkCommandNames[0], @path) diff --git a/ext/tk/lib/tk/scrollbar.rb b/ext/tk/lib/tk/scrollbar.rb index 66eadbd65..521fc7e40 100644 --- a/ext/tk/lib/tk/scrollbar.rb +++ b/ext/tk/lib/tk/scrollbar.rb @@ -19,9 +19,24 @@ class Tk::Scrollbar<TkWindow } if keys and keys != None - #tk_call_without_enc('scrollbar', @path, *hash_kv(keys, true)) - tk_call_without_enc(self.class::TkCommandNames[0], @path, - *hash_kv(keys, true)) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + #tk_call_without_enc('scrollbar', @path, *hash_kv(keys, true)) + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + else + begin + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + rescue + tk_call_without_enc(self.class::TkCommandNames[0], @path) + keys = __check_available_configure_options(keys) + unless keys.empty? + tk_call_without_enc('destroy', @path) + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + end + end + end else #tk_call_without_enc('scrollbar', @path) tk_call_without_enc(self.class::TkCommandNames[0], @path) @@ -103,6 +118,26 @@ class Tk::Scrollbar<TkWindow def activate(element=None) tk_send_without_enc('activate', element) end + + def moveto(fraction) + tk_send_without_enc('moveto', fraction) + self + end + + def scroll(*args) + tk_send_without_enc('scroll', *args) + self + end + + def scroll_units(num) + scroll(num, 'units') + self + end + + def scroll_pages(num) + scroll(num, 'pages') + self + end end #TkScrollbar = Tk::Scrollbar unless Object.const_defined? :TkScrollbar diff --git a/ext/tk/lib/tk/spinbox.rb b/ext/tk/lib/tk/spinbox.rb index e7f223aea..e372c5800 100644 --- a/ext/tk/lib/tk/spinbox.rb +++ b/ext/tk/lib/tk/spinbox.rb @@ -37,6 +37,22 @@ class Tk::Spinbox<Tk::Entry nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) diff --git a/ext/tk/lib/tk/text.rb b/ext/tk/lib/tk/text.rb index 2ed1d30cf..14b9be23f 100644 --- a/ext/tk/lib/tk/text.rb +++ b/ext/tk/lib/tk/text.rb @@ -250,7 +250,11 @@ class Tk::Text<TkTextWin def self.new(*args, &block) obj = super(*args){} obj.init_instance_variable - obj.instance_eval(&block) if defined? yield + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + obj.instance_exec(obj, &block) if defined? yield + else + obj.instance_eval(&block) if defined? yield + end obj end @@ -260,8 +264,12 @@ class Tk::Text<TkTextWin end def __destroy_hook__ - TkTextTag::TTagID_TBL.delete(@path) - TkTextMark::TMarkID_TBL.delete(@path) + TkTextTag::TTagID_TBL.mutex.synchronize{ + TkTextTag::TTagID_TBL.delete(@path) + } + TkTextTag::TMarkID_TBL.mutex.synchronize{ + TkTextMark::TMarkID_TBL.delete(@path) + } end def create_self(keys) @@ -712,15 +720,17 @@ class Tk::Text<TkTextWin def tag_delete(*tags) tk_send_without_enc('tag', 'delete', *(tags.collect{|tag| _get_eval_enc_str(tag)})) - if TkTextTag::TTagID_TBL[@path] - tags.each{|tag| - if tag.kind_of?(TkTextTag) - TkTextTag::TTagID_TBL[@path].delete(tag.id) - else - TkTextTag::TTagID_TBL[@path].delete(tag) - end - } - end + TkTextTag::TTagID_TBL.mutex.synchronize{ + if TkTextTag::TTagID_TBL[@path] + tags.each{|tag| + if tag.kind_of?(TkTextTag) + TkTextTag::TTagID_TBL[@path].delete(tag.id) + else + TkTextTag::TTagID_TBL[@path].delete(tag) + end + } + end + } self end alias deltag tag_delete diff --git a/ext/tk/lib/tk/textmark.rb b/ext/tk/lib/tk/textmark.rb index 6ce52b58d..72c1ce1ab 100644 --- a/ext/tk/lib/tk/textmark.rb +++ b/ext/tk/lib/tk/textmark.rb @@ -8,14 +8,26 @@ class TkTextMark<TkObject include Tk::Text::IndexModMethods TMarkID_TBL = TkCore::INTERP.create_table - Tk_TextMark_ID = ['mark'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TMarkID_TBL.clear } + (Tk_TextMark_ID = ['mark'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + TMarkID_TBL.mutex.synchronize{ TMarkID_TBL.clear } + } def TkTextMark.id2obj(text, id) tpath = text.path - return id unless TMarkID_TBL[tpath] - TMarkID_TBL[tpath][id]? TMarkID_TBL[tpath][id]: id + TMarkID_TBL.mutex.synchronize{ + if TMarkID_TBL[tpath] + TMarkID_TBL[tpath][id]? TMarkID_TBL[tpath][id]: id + else + id + end + } end def initialize(parent, index) @@ -24,12 +36,16 @@ class TkTextMark<TkObject #end @parent = @t = parent @tpath = parent.path - # @path = @id = Tk_TextMark_ID.join('') - @path = @id = Tk_TextMark_ID.join(TkCore::INTERP._ip_id_).freeze - TMarkID_TBL[@id] = self - TMarkID_TBL[@tpath] = {} unless TMarkID_TBL[@tpath] - TMarkID_TBL[@tpath][@id] = self - Tk_TextMark_ID[1].succ! + Tk_TextMark_ID.mutex.synchronize{ + # @path = @id = Tk_TextMark_ID.join('') + @path = @id = Tk_TextMark_ID.join(TkCore::INTERP._ip_id_).freeze + Tk_TextMark_ID[1].succ! + } + TMarkID_TBL.mutex.synchronize{ + TMarkID_TBL[@id] = self + TMarkID_TBL[@tpath] = {} unless TMarkID_TBL[@tpath] + TMarkID_TBL[@tpath][@id] = self + } tk_call_without_enc(@t.path, 'mark', 'set', @id, _get_eval_enc_str(index)) @t._addtag id, self @@ -124,27 +140,44 @@ end TktMark = TkTextMark class TkTextNamedMark<TkTextMark - def self.new(parent, name, *args) - if TMarkID_TBL[parent.path] && TMarkID_TBL[parent.path][name] - return TMarkID_TBL[parent.path][name] - else - super(parent, name, *args) - end + def self.new(parent, name, index=nil) + TMarkID_TBL.mutex.synchronize{ + if TMarkID_TBL[parent.path] && TMarkID_TBL[parent.path][name] + obj = TMarkID_TBL[parent.path][name] + else + # super(parent, name, *args) + (obj = self.allocate).instance_eval{ + @parent = @t = parent + @tpath = parent.path + @path = @id = name + TMarkID_TBL[@id] = self + TMarkID_TBL[@tpath] = {} unless TMarkID_TBL[@tpath] + TMarkID_TBL[@tpath][@id] = self unless TMarkID_TBL[@tpath][@id] + @t._addtag @id, self + } + obj + end + + if obj && index + tk_call_without_enc(parent.path, 'mark', 'set', name, + _get_eval_enc_str(index)) + end + obj + } end def initialize(parent, name, index=nil) + # dummy:: not called by 'new' method + #unless parent.kind_of?(Tk::Text) # fail ArgumentError, "expect Tk::Text for 1st argument" #end @parent = @t = parent @tpath = parent.path @path = @id = name - TMarkID_TBL[@id] = self - TMarkID_TBL[@tpath] = {} unless TMarkID_TBL[@tpath] - TMarkID_TBL[@tpath][@id] = self unless TMarkID_TBL[@tpath][@id] tk_call_without_enc(@t.path, 'mark', 'set', @id, _get_eval_enc_str(index)) if index - @t._addtag id, self + @t._addtag @id, self end end TktNamedMark = TkTextNamedMark diff --git a/ext/tk/lib/tk/texttag.rb b/ext/tk/lib/tk/texttag.rb index 8264d5293..792d544fe 100644 --- a/ext/tk/lib/tk/texttag.rb +++ b/ext/tk/lib/tk/texttag.rb @@ -10,14 +10,26 @@ class TkTextTag<TkObject include Tk::Text::IndexModMethods TTagID_TBL = TkCore::INTERP.create_table - Tk_TextTag_ID = ['tag'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TTagID_TBL.clear } + (Tk_TextTag_ID = ['tag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + TTagID_TBL.mutex.synchronize{ TTagID_TBL.clear } + } def TkTextTag.id2obj(text, id) tpath = text.path - return id unless TTagID_TBL[tpath] - TTagID_TBL[tpath][id]? TTagID_TBL[tpath][id]: id + TTagID_TBL.mutex.synchronize{ + if TTagID_TBL[tpath] + TTagID_TBL[tpath][id]? TTagID_TBL[tpath][id]: id + else + id + end + } end def initialize(parent, *args) @@ -26,12 +38,16 @@ class TkTextTag<TkObject #end @parent = @t = parent @tpath = parent.path - # @path = @id = Tk_TextTag_ID.join('') - @path = @id = Tk_TextTag_ID.join(TkCore::INTERP._ip_id_).freeze - # TTagID_TBL[@id] = self - TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath] - TTagID_TBL[@tpath][@id] = self - Tk_TextTag_ID[1].succ! + Tk_TextTag_ID.mutex.synchronize{ + # @path = @id = Tk_TextTag_ID.join('') + @path = @id = Tk_TextTag_ID.join(TkCore::INTERP._ip_id_).freeze + Tk_TextTag_ID[1].succ! + } + TTagID_TBL.mutex.synchronize{ + TTagID_TBL[@id] = self + TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath] + TTagID_TBL[@tpath][@id] = self + } #tk_call @t.path, "tag", "configure", @id, *hash_kv(keys) if args != [] keys = args.pop @@ -221,7 +237,9 @@ class TkTextTag<TkObject def destroy tk_call_without_enc(@t.path, 'tag', 'delete', @id) - TTagID_TBL[@tpath].delete(@id) if TTagID_TBL[@tpath] + TTagID_TBL.mutex.synchronize{ + TTagID_TBL[@tpath].delete(@id) if TTagID_TBL[@tpath] + } self end end @@ -229,33 +247,48 @@ TktTag = TkTextTag class TkTextNamedTag<TkTextTag def self.new(parent, name, *args) - if TTagID_TBL[parent.path] && TTagID_TBL[parent.path][name] - tagobj = TTagID_TBL[parent.path][name] - if args != [] - keys = args.pop - if keys.kind_of?(Hash) - tagobj.add(*args) if args != [] - tagobj.configure(keys) - else - args.push keys - tagobj.add(*args) - end + tagobj = nil + TTagID_TBL.mutex.synchronize{ + if TTagID_TBL[parent.path] && TTagID_TBL[parent.path][name] + tagobj = TTagID_TBL[parent.path][name] + else + # super(parent, name, *args) + (tagobj = self.allocate).instance_eval{ + @parent = @t = parent + @tpath = parent.path + @path = @id = name + TTagID_TBL[@id] = self + TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath] + TTagID_TBL[@tpath][@id] = self unless TTagID_TBL[@tpath][@id] + @t._addtag @id, self + } + end + } + + if args != [] + keys = args.pop + if keys.kind_of?(Hash) + tagobj.add(*args) if args != [] + tagobj.configure(keys) + else + args.push keys + tagobj.add(*args) end - return tagobj - else - super(parent, name, *args) end + + tagobj end def initialize(parent, name, *args) + # dummy:: not called by 'new' method + #unless parent.kind_of?(Tk::Text) # fail ArgumentError, "expect Tk::Text for 1st argument" #end @parent = @t = parent @tpath = parent.path @path = @id = name - TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath] - TTagID_TBL[@tpath][@id] = self unless TTagID_TBL[@tpath][@id] + #if mode # tk_call @t.path, "addtag", @id, *args #end @@ -269,7 +302,7 @@ class TkTextNamedTag<TkTextTag add(*args) end end - @t._addtag id, self + @t._addtag @id, self end end TktNamedTag = TkTextNamedTag diff --git a/ext/tk/lib/tk/timer.rb b/ext/tk/lib/tk/timer.rb index 47f2b7935..3588f0c48 100644 --- a/ext/tk/lib/tk/timer.rb +++ b/ext/tk/lib/tk/timer.rb @@ -11,7 +11,12 @@ class TkTimer TkCommandNames = ['after'.freeze].freeze - Tk_CBID = ['a'.freeze, '00000'.taint].freeze + (Tk_CBID = ['a'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + Tk_CBTBL = {}.taint TkCore::INTERP.add_tk_procs('rb_after', 'id', <<-'EOL') @@ -96,9 +101,9 @@ class TkTimer return self end @after_script = "rb_after #{@id}" - @after_id = tk_call_without_enc('after', sleep, @after_script) @current_args = args @current_script = [sleep, @after_script] + @after_id = tk_call_without_enc('after', sleep, @after_script) self end @@ -138,9 +143,11 @@ class TkTimer end def initialize(*args, &b) - # @id = Tk_CBID.join('') - @id = Tk_CBID.join(TkCore::INTERP._ip_id_) - Tk_CBID[1].succ! + Tk_CBID.mutex.synchronize{ + # @id = Tk_CBID.join('') + @id = Tk_CBID.join(TkCore::INTERP._ip_id_) + Tk_CBID[1].succ! + } @wait_var = TkVariable.new(0) diff --git a/ext/tk/lib/tk/ttk_selector.rb b/ext/tk/lib/tk/ttk_selector.rb index f89b5c76b..72ed637a3 100644 --- a/ext/tk/lib/tk/ttk_selector.rb +++ b/ext/tk/lib/tk/ttk_selector.rb @@ -56,6 +56,15 @@ module Tk @TOPLEVEL_ALIAS_TABLE[:Tile] = @TOPLEVEL_ALIAS_TABLE[:Ttk] ################################################ + # register some Ttk widgets as default + # (Ttk is a standard library on Tcl/Tk8.5+) + @TOPLEVEL_ALIAS_TABLE[:Ttk].each{|sym, file| + unless Object.autoload?(sym) || Object.const_defined?(sym) + Object.autoload(sym, file) + end + } + + ################################################ @TOPLEVEL_ALIAS_SETUP_PROC[:Tile] = @TOPLEVEL_ALIAS_SETUP_PROC[:Ttk] = proc{|mod| diff --git a/ext/tk/lib/tk/validation.rb b/ext/tk/lib/tk/validation.rb index 0c5b5c61b..1da38c776 100644 --- a/ext/tk/lib/tk/validation.rb +++ b/ext/tk/lib/tk/validation.rb @@ -249,6 +249,22 @@ class TkValidateCommand nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); # diff --git a/ext/tk/lib/tk/variable.rb b/ext/tk/lib/tk/variable.rb index 632f00ced..f738a96ee 100644 --- a/ext/tk/lib/tk/variable.rb +++ b/ext/tk/lib/tk/variable.rb @@ -16,7 +16,18 @@ class TkVariable #TkVar_ID_TBL = {} TkVar_CB_TBL = TkCore::INTERP.create_table TkVar_ID_TBL = TkCore::INTERP.create_table - Tk_VARIABLE_ID = ["v".freeze, "00000".taint].freeze + (Tk_VARIABLE_ID = ["v".freeze, "00000".taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + TkCore::INTERP.init_ip_env{ + TkVar_CB_TBL.mutex.synchronize{ TkVar_CB_TBL.clear } + TkVar_ID_TBL.mutex.synchronize{ TkVar_ID_TBL.clear } + } + + major, minor, type, type_name, patchlevel = TclTkLib.get_version + USE_OLD_TRACE_OPTION_STYLE = (major < 8) || (major == 8 && minor < 4) #TkCore::INTERP.add_tk_procs('rb_var', 'args', # "ruby [format \"TkVariable.callback %%Q!%s!\" $args]") @@ -44,10 +55,10 @@ class TkVariable def TkVariable.callback(id, name1, name2, op) #name1,name2,op = tk_split_list(args) #name1,name2,op = tk_split_simplelist(args) - if TkVar_CB_TBL[id] + if cb_obj = TkVar_CB_TBL[id] #_get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op)) begin - _get_eval_string(TkVar_CB_TBL[id].trace_callback(name2, op)) + _get_eval_string(cb_obj.trace_callback(name2, op)) rescue SystemExit exit(0) rescue Interrupt @@ -59,7 +70,11 @@ class TkVariable "\n---< backtrace of Ruby side >-----\n" + _toUTF8(e.backtrace.join("\n")) + "\n---< backtrace of Tk side >-------" - msg.instance_variable_set(:@encoding, 'utf-8') + if TkCore::WITH_ENCODING + msg.force_encoding('utf-8') + else + msg.instance_variable_set(:@encoding, 'utf-8') + end rescue Exception msg = e.class.inspect + ': ' + e.message + "\n" + "\n---< backtrace of Ruby side >-----\n" + @@ -267,11 +282,15 @@ class TkVariable def initialize(val="", type=nil) # @id = Tk_VARIABLE_ID.join('') begin - @id = Tk_VARIABLE_ID.join(TkCore::INTERP._ip_id_) - Tk_VARIABLE_ID[1].succ! + Tk_VARIABLE_ID.mutex.synchronize{ + @id = Tk_VARIABLE_ID.join(TkCore::INTERP._ip_id_) + Tk_VARIABLE_ID[1].succ! + } end until INTERP._invoke_without_enc('info', 'globals', @id).empty? - TkVar_ID_TBL[@id] = self + TkVar_ID_TBL.mutex.synchronize{ + TkVar_ID_TBL[@id] = self + } @var = @id @elem = nil @@ -1263,56 +1282,101 @@ end end end + def _check_trace_opt(opts) + if opts.kind_of?(Array) + opt_str = opts.map{|s| s.to_s}.join(' ') + else + opt_str = opts.to_s + end + + fail ArgumentError, 'null trace option' if opt_str.empty? + + if opt_str =~ /[^arwu\s]/ + # new format (Tcl/Tk8.4+?) + if opts.kind_of?(Array) + opt_ary = opts.map{|opt| opt.to_s.strip} + else + opt_ary = opt_str.split(/\s+|\|/) + opt_ary.delete('') + end + if USE_OLD_TRACE_OPTION_STYLE + opt_ary.uniq.map{|opt| + case opt + when 'array' + 'a' + when 'read' + 'r' + when 'write' + 'w' + when 'unset' + 'u' + else + fail ArgumentError, "unsupported trace option '#{opt}' on Tcl/Tk#{Tk::TCL_PATCHLEVEL}" + end + }.join + else + opt_ary + end + else + # old format + opt_ary = opt_str.delete('^arwu').split(//).uniq + if USE_OLD_TRACE_OPTION_STYLE + opt_ary.join + else + opt_ary.map{|c| + case c + when 'a' + 'array' + when 'r' + 'read' + when 'w' + 'write' + when 'u' + 'unset' + end + } + end + end + end + private :_check_trace_opt + def trace(opts, cmd = Proc.new) - @trace_var = [] if @trace_var == nil - #opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') - opts = opts.to_s - opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') - @trace_var.unshift([opts,cmd]) + opts = _check_trace_opt(opts) + (@trace_var ||= []).unshift([opts,cmd]) + if @trace_opts == nil TkVar_CB_TBL[@id] = self - @trace_opts = opts.dup - Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 - Tk.tk_call_without_enc('trace', 'add', 'variable', - @id, @trace_opts, 'rb_var') + @trace_opts = opts + if USE_OLD_TRACE_OPTION_STYLE + Tk.tk_call_without_enc('trace', 'variable', + @id, @trace_opts, 'rb_var ' << @id) else - # TCL_VERSION <= 8.3 - Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var') + Tk.tk_call_without_enc('trace', 'add', 'variable', + @id, @trace_opts, 'rb_var ' << @id) end -=end else newopts = @trace_opts.dup - #opts.each_byte{|c| newopts += c.chr unless newopts.index(c)} - opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)} - if newopts != @trace_opts - Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, - 'rb_var ' << @id) - @trace_opts.replace(newopts) - Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 - Tk.tk_call_without_enc('trace', 'remove', 'variable', - @id, @trace_opts, 'rb_var') - @trace_opts.replace(newopts) - Tk.tk_call_without_enc('trace', 'add', 'variable', - @id, @trace_opts, 'rb_var') - else - # TCL_VERSION <= 8.3 + if USE_OLD_TRACE_OPTION_STYLE + opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} + if newopts != @trace_opts Tk.tk_call_without_enc('trace', 'vdelete', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) @trace_opts.replace(newopts) Tk.tk_call_without_enc('trace', 'variable', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) + end + else + newopts |= opts + unless (newopts - @trace_opts).empty? + Tk.tk_call_without_enc('trace', 'remove', 'variable', + @id, @trace_opts, 'rb_var ' << @id) + @trace_opts.replace(newopts) + Tk.tk_call_without_enc('trace', 'add', 'variable', + @id, @trace_opts, 'rb_var ' << @id) end -=end end end + self end @@ -1321,65 +1385,54 @@ end fail(RuntimeError, "invalid for a TkVariable which denotes an element of Tcl's array") end - @trace_elem = {} if @trace_elem == nil - @trace_elem[elem] = [] if @trace_elem[elem] == nil - opts = opts.to_s - opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') - @trace_elem[elem].unshift([opts,cmd]) + + opts = _check_trace_opt(opts) + + ((@trace_elem ||= {})[elem] ||= []).unshift([opts,cmd]) + if @trace_opts == nil TkVar_CB_TBL[@id] = self - @trace_opts = opts.dup - Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 + @trace_opts = opts + if USE_OLD_TRACE_OPTION_STYLE Tk.tk_call_without_enc('trace', 'add', 'variable', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) else - # TCL_VERSION <= 8.3 Tk.tk_call_without_enc('trace', 'variable', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) end -=end else newopts = @trace_opts.dup - # opts.each_byte{|c| newopts += c.chr unless newopts.index(c)} - opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)} - if newopts != @trace_opts - Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, - 'rb_var ' << @id) - @trace_opts.replace(newopts) - Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 - Tk.tk_call_without_enc('trace', 'remove', 'variable', - @id, @trace_opts, 'rb_var') - @trace_opts.replace(newopts) - Tk.tk_call_without_enc('trace', 'add', 'variable', - @id, @trace_opts, 'rb_var') - else - # TCL_VERSION <= 8.3 + if USE_OLD_TRACE_OPTION_STYLE + opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} + if newopts != @trace_opts Tk.tk_call_without_enc('trace', 'vdelete', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) @trace_opts.replace(newopts) Tk.tk_call_without_enc('trace', 'variable', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) + end + else + newopts |= opts + unless (newopts - @trace_opts).empty? + Tk.tk_call_without_enc('trace', 'remove', 'variable', + @id, @trace_opts, 'rb_var ' << @id) + @trace_opts.replace(newopts) + Tk.tk_call_without_enc('trace', 'add', 'variable', + @id, @trace_opts, 'rb_var ' << @id) end -=end end end + self end - def trace_vinfo + def trace_info return [] unless @trace_var @trace_var.dup end + alias trace_vinfo trace_info - def _trace_vinfo_for_element(elem) + def trace_info_for_element(elem) if @elem fail(RuntimeError, "invalid for a TkVariable which denotes an element of Tcl's array") @@ -1388,141 +1441,180 @@ end return [] unless @trace_elem[elem] @trace_elem[elem].dup end + alias trace_vinfo_for_element trace_info_for_element - def trace_vdelete(opts,cmd) + def trace_remove(opts,cmd) return self unless @trace_var.kind_of? Array - opts = opts.to_s - opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') + + opts = _check_trace_opt(opts) + idx = -1 - newopts = '' - @trace_var.each_with_index{|e,i| - if idx < 0 && e[0] == opts && e[1] == cmd - idx = i - next - end - # e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} - e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)} - } + if USE_OLD_TRACE_OPTION_STYLE + newopts = '' + @trace_var.each_with_index{|e, i| + if idx < 0 && e[1] == cmd + diff = false + ['a', 'r', 'w', 'u'].each{|c| + break if (diff = e[0].index(c) ^ opts.index(c)) + } + unless diff + #find + idx = i + next + end + end + e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} + } + else + newopts = [] + @trace_var.each_with_index{|e, i| + if idx < 0 && e[1] == cmd && + e[0].size == opts.size && (e[0] - opts).empty? + # find + idx = i + next + end + newopts |= e[0] + } + end + if idx >= 0 @trace_var.delete_at(idx) else return self end - @trace_elem.each{|elem| + (@trace_elem ||= {}).each{|elem| @trace_elem[elem].each{|e| - # e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} - e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)} + if USE_OLD_TRACE_OPTION_STYLE + e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} + else + newopts |= e[0] + end } } - newopts = newopts.to_s - newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('') - if newopts != @trace_opts - Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 - Tk.tk_call_without_enc('trace', 'remove', 'variable', - @id, @trace_opts, 'rb_var') - else - # TCL_VERSION <= 8.3 + if USE_OLD_TRACE_OPTION_STYLE + diff = false + @trace_opts.each_byte{|c| break if (diff = ! newopts.index(c))} + if diff Tk.tk_call_without_enc('trace', 'vdelete', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) + @trace_opts.replace(newopts) + unless @trace_opts.empty? + Tk.tk_call_without_enc('trace', 'variable', + @id, @trace_opts, 'rb_var ' << @id) + end end -=end - @trace_opts.replace(newopts) - if @trace_opts != '' - Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 + else + unless (@trace_opts - newopts).empty? + Tk.tk_call_without_enc('trace', 'remove', 'variable', + @id, @trace_opts, 'rb_var ' << @id) + @trace_opts.replace(newopts) + unless @trace_opts.empty? Tk.tk_call_without_enc('trace', 'add', 'variable', - @id, @trace_opts, 'rb_var') - else - # TCL_VERSION <= 8.3 - Tk.tk_call_without_enc('trace', 'variable', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) end -=end end end self end + alias trace_delete trace_remove + alias trace_vdelete trace_remove - def trace_vdelete_for_element(elem,opts,cmd) + def trace_remove_for_element(elem,opts,cmd) if @elem fail(RuntimeError, "invalid for a TkVariable which denotes an element of Tcl's array") end return self unless @trace_elem.kind_of? Hash return self unless @trace_elem[elem].kind_of? Array - opts = opts.to_s - opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') + + opts = _check_trace_opt(opts) + idx = -1 - @trace_elem[elem].each_with_index{|e,i| - if idx < 0 && e[0] == opts && e[1] == cmd - idx = i - next - end - } + if USE_OLD_TRACE_OPTION_STYLE + @trace_elem[elem].each_with_index{|e, i| + if idx < 0 && e[1] == cmd + diff = false + ['a', 'r', 'w', 'u'].each{|c| + break if (diff = e[0].index(c) ^ opts.index(c)) + } + unless diff + #find + idx = i + next + end + end + } + else + @trace_elem[elem].each_with_index{|e, i| + if idx < 0 && e[1] == cmd && + e[0].size == opts.size && (e[0] - opts).empty? + # find + idx = i + next + end + } + end + if idx >= 0 @trace_elem[elem].delete_at(idx) else return self end - newopts = '' - @trace_var.each{|e| - # e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} - e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)} - } - @trace_elem.each{|elem| - @trace_elem[elem].each{|e| - # e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} - e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)} + if USE_OLD_TRACE_OPTION_STYLE + newopts = '' + @trace_var.each{|e| + e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} } - } + @trace_elem.each{|elem| + @trace_elem[elem].each{|e| + e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} + } + } + else + newopts = [] + @trace_var.each{|e| + newopts |= e[0] + } + @trace_elem.each{|elem| + @trace_elem[elem].each{|e| + e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} + } + } + end - newopts = newopts.to_s - newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('') - if newopts != @trace_opts - Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 - Tk.tk_call_without_enc('trace', 'remove', 'variable', - @id, @trace_opts, 'rb_var') - else - # TCL_VERSION <= 8.3 + if USE_OLD_TRACE_OPTION_STYLE + diff = false + @trace_opts.each_byte{|c| break if (diff = ! newopts.index(c))} + if diff Tk.tk_call_without_enc('trace', 'vdelete', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) + @trace_opts.replace(newopts) + unless @trace_opts.empty? + Tk.tk_call_without_enc('trace', 'variable', + @id, @trace_opts, 'rb_var ' << @id) + end end -=end - @trace_opts.replace(newopts) - if @trace_opts != '' - Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 + else + unless (@trace_opts - newopts).empty? + Tk.tk_call_without_enc('trace', 'remove', 'variable', + @id, @trace_opts, 'rb_var ' << @id) + @trace_opts.replace(newopts) + unless @trace_opts.empty? Tk.tk_call_without_enc('trace', 'add', 'variable', - @id, @trace_opts, 'rb_var') - else - # TCL_VERSION <= 8.3 - Tk.tk_call_without_enc('trace', 'variable', @id, - @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) end -=end end end self end + alias trace_delete_for_element trace_remove_for_element + alias trace_vdelete_for_element trace_remove_for_element end class TkVarAccess<TkVariable @@ -1532,12 +1624,23 @@ class TkVarAccess<TkVariable return name end - if v = TkVar_ID_TBL[name] - v.value = args[0] unless args.empty? - return v - end + name = name.to_s + v = nil + TkVar_ID_TBL.mutex.synchronize{ + if v = TkVar_ID_TBL[name] + v.value = args[0] unless args.empty? + return v + else + (v = self.allocate).instance_eval{ + @id = name + TkVar_ID_TBL[@id] = self + @var = @id + } + end + } - super(name, *args) + v.instance_eval{ initialize(name, *args) } + v end def self.new_hash(name, *args) @@ -1549,27 +1652,38 @@ class TkVarAccess<TkVariable return name end - if v = TkVar_ID_TBL[name] - unless v.is_hash? - fail ArgumentError, "already exist as a scalar variable" + name = name.to_s + v = nil + TkVar_ID_TBL.mutex.synchronize{ + if v = TkVar_ID_TBL[name] + unless v.is_hash? + fail ArgumentError, "already exist as a scalar variable" + end + v.value = args[0] unless args.empty? + return v + else + (v = self.allocate).instance_eval{ + @id = name + TkVar_ID_TBL[@id] = self + @var = @id + } end - v.value = args[0] unless args.empty? - return v - end + } INTERP._invoke_without_enc('global', name) if args.empty? && INTERP._invoke_without_enc('array', 'exist', name) == '0' - self.new(name, {}) # force creating + v.instance_eval{ initialize(name, {}) } # force creating else - self.new(name, *args) + v.instance_eval{ initialize(name, *args) } end + v end def initialize(varname, val=nil) - @id = varname - TkVar_ID_TBL[@id] = self + # @id = varname + # TkVar_ID_TBL[@id] = self - @var = @id + # @var = @id @elem = nil @def_default = false diff --git a/ext/tk/lib/tk/virtevent.rb b/ext/tk/lib/tk/virtevent.rb index d47e80aec..ae31ac1f8 100644 --- a/ext/tk/lib/tk/virtevent.rb +++ b/ext/tk/lib/tk/virtevent.rb @@ -9,10 +9,17 @@ class TkVirtualEvent<TkObject TkCommandNames = ['event'.freeze].freeze - TkVirtualEventID = ["VirtEvent".freeze, "00000".taint].freeze + (TkVirtualEventID = ["VirtEvent".freeze, "00000".taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + TkVirtualEventTBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ TkVirtualEventTBL.clear } + TkCore::INTERP.init_ip_env{ + TkVirtualEventTBL.mutex.synchronize{ TkVirtualEventTBL.clear } + } class PreDefVirtEvent<self def self.new(event, *sequences) @@ -21,22 +28,30 @@ class TkVirtualEvent<TkObject elsif event !~ /^<.*>$/ event = '<' + event + '>' end - if TkVirtualEvent::TkVirtualEventTBL.has_key?(event) - TkVirtualEvent::TkVirtualEventTBL[event] - else - super(event, *sequences) - end + TkVirtualEvent::TkVirtualEventTBL.mutex.synchronize{ + if TkVirtualEvent::TkVirtualEventTBL.has_key?(event) + TkVirtualEvent::TkVirtualEventTBL[event] + else + # super(event, *sequences) + (obj = self.allocate).instance_eval{ + initialize(event, *sequences) + TkVirtualEvent::TkVirtualEventTBL[@id] = self + } + end + } end def initialize(event, *sequences) @path = @id = event - TkVirtualEvent::TkVirtualEventTBL[@id] = self - add(*sequences) + _add_sequences(sequences) end end def TkVirtualEvent.getobj(event) - obj = TkVirtualEventTBL[event] + obj = nil + TkVirtualEventTBL.mutex.synchronize{ + obj = TkVirtualEventTBL[event] + } if obj obj else @@ -55,19 +70,31 @@ class TkVirtualEvent<TkObject end def initialize(*sequences) - # @path = @id = '<' + TkVirtualEventID.join('') + '>' - @path = @id = '<' + TkVirtualEventID.join(TkCore::INTERP._ip_id_) + '>' - TkVirtualEventID[1].succ! - add(*sequences) + TkVirtualEventID.mutex.synchronize{ + # @path = @id = '<' + TkVirtualEventID.join('') + '>' + @path = @id = '<' + TkVirtualEventID.join(TkCore::INTERP._ip_id_) + '>' + TkVirtualEventID[1].succ! + } + _add_sequences(sequences) end - def add(*sequences) - if sequences != [] + def _add_sequences(seq_ary) + unless seq_ary.empty? tk_call_without_enc('event', 'add', "<#{@id}>", - *(sequences.collect{|seq| + *(seq_ary.collect{|seq| "<#{tk_event_sequence(seq)}>" }) ) - TkVirtualEventTBL[@id] = self + end + self + end + private :_add_sequences + + def add(*sequences) + if sequences != [] + _add_sequences(sequences) + TkVirtualEventTBL.mutex.synchronize{ + TkVirtualEventTBL[@id] = self + } end self end @@ -75,20 +102,26 @@ class TkVirtualEvent<TkObject def delete(*sequences) if sequences == [] tk_call_without_enc('event', 'delete', "<#{@id}>") - TkVirtualEventTBL.delete(@id) + TkVirtualEventTBL.mutex.synchronize{ + TkVirtualEventTBL.delete(@id) + } else tk_call_without_enc('event', 'delete', "<#{@id}>", *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>" }) ) - TkVirtualEventTBL.delete(@id) if info == [] + if tk_call_without_enc('event','info',"<#{@id}>").empty? + TkVirtualEventTBL.mutex.synchronize{ + TkVirtualEventTBL.delete(@id) + } + end end self end def info tk_call_without_enc('event','info',"<#{@id}>").split(/\s+/).collect!{|seq| - l = seq.scan(/<*[^<>]+>*/).collect!{|subseq| + lst = seq.scan(/<*[^<>]+>*/).collect!{|subseq| case (subseq) when /^<<[^<>]+>>$/ TkVirtualEvent.getobj(subseq[1..-2]) @@ -98,7 +131,7 @@ class TkVirtualEvent<TkObject subseq.split('') end }.flatten - (l.size == 1) ? l[0] : l + (lst.size == 1) ? lst[0] : lst } end end diff --git a/ext/tk/lib/tk/wm.rb b/ext/tk/lib/tk/wm.rb index 1f432a384..49dd4d73c 100644 --- a/ext/tk/lib/tk/wm.rb +++ b/ext/tk/lib/tk/wm.rb @@ -5,273 +5,407 @@ require 'tk' module Tk module Wm - include TkComm + #include TkComm + extend TkCore TkCommandNames = ['wm'.freeze].freeze TOPLEVEL_METHODCALL_OPTKEYS = {} - def aspect(*args) + def Wm.aspect(win, *args) if args.length == 0 - list(tk_call_without_enc('wm', 'aspect', path)) + list(tk_call_without_enc('wm', 'aspect', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call('wm', 'aspect', path, *args) - self + tk_call('wm', 'aspect', win.epath, *args) + win end end + def aspect(*args) + Wm.aspect(self, *args) + end + alias wm_aspect aspect TOPLEVEL_METHODCALL_OPTKEYS['aspect'] = 'aspect' - def attributes(slot=nil,value=None) + def Wm.attributes(win, slot=nil,value=TkComm::None) if slot == nil - lst = tk_split_list(tk_call('wm', 'attributes', path)) + lst = tk_split_list(tk_call('wm', 'attributes', win.epath)) info = {} while key = lst.shift info[key[1..-1]] = lst.shift end info elsif slot.kind_of? Hash - tk_call('wm', 'attributes', path, *hash_kv(slot)) - self - elsif value == None - tk_call('wm', 'attributes', path, "-#{slot}") + tk_call('wm', 'attributes', win.epath, *hash_kv(slot)) + win + elsif value == TkComm::None + tk_call('wm', 'attributes', win.epath, "-#{slot}") else - tk_call('wm', 'attributes', path, "-#{slot}", value) - self + tk_call('wm', 'attributes', win.epath, "-#{slot}", value) + win end end + def attributes(slot=nil,value=TkComm::None) + Wm.attributes(self, slot, value) + end + alias wm_attributes attributes TOPLEVEL_METHODCALL_OPTKEYS['attributes'] = 'attributes' - def client(name=None) - if name == None - tk_call('wm', 'client', path) + def Wm.client(win, name=TkComm::None) + if name == TkComm::None + tk_call('wm', 'client', win.epath) else name = '' if name == nil - tk_call('wm', 'client', path, name) - self + tk_call('wm', 'client', win.epath, name) + win end end + def client(name=TkComm::None) + Wm.client(self, name) + end + alias wm_client client TOPLEVEL_METHODCALL_OPTKEYS['client'] = 'client' - def colormapwindows(*args) + def Wm.colormapwindows(win, *args) if args.size == 0 - list(tk_call_without_enc('wm', 'colormapwindows', path)) + list(tk_call_without_enc('wm', 'colormapwindows', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call_without_enc('wm', 'colormapwindows', path, *args) - self + tk_call_without_enc('wm', 'colormapwindows', win.epath, *args) + win end end + def colormapwindows(*args) + Wm.colormapwindows(self, *args) + end + alias wm_colormapwindows colormapwindows TOPLEVEL_METHODCALL_OPTKEYS['colormapwindows'] = 'colormapwindows' - def wm_command(value=nil) + def Wm.command(win, value=nil) if value - tk_call('wm', 'command', path, value) - self + tk_call('wm', 'command', epath, value) + win else - #procedure(tk_call('wm', 'command', path)) - tk_call('wm', 'command', path) + #procedure(tk_call('wm', 'command', epath)) + tk_call('wm', 'command', epath) end end + def wm_command(value=nil) + Wm.command(self, value) + end TOPLEVEL_METHODCALL_OPTKEYS['wm_command'] = 'wm_command' - def deiconify(ex = true) + def Wm.deiconify(win, ex = true) if ex - tk_call_without_enc('wm', 'deiconify', path) + tk_call_without_enc('wm', 'deiconify', win.epath) else - self.iconify + Wm.iconify(win) end - self + win end + def deiconify(ex = true) + Wm.deiconify(self, ex) + end + alias wm_deiconify deiconify - def focusmodel(mode = nil) + def Wm.focusmodel(win, mode = nil) if mode - tk_call_without_enc('wm', 'focusmodel', path, mode) - self + tk_call_without_enc('wm', 'focusmodel', win.epath, mode) + win else - tk_call_without_enc('wm', 'focusmodel', path) + tk_call_without_enc('wm', 'focusmodel', win.epath) end end + def focusmodel(mode = nil) + Wm.focusmodel(self, mode) + end + alias wm_focusmodel focusmodel TOPLEVEL_METHODCALL_OPTKEYS['focusmodel'] = 'focusmodel' + def Wm.forget(win) + # Tcl/Tk 8.5+ + # work with dockable frames + tk_call_without_enc('wm', 'forget', win.epath) + win + end + def wm_forget + Wm.forget(self) + end + + def Wm.frame(win) + tk_call_without_enc('wm', 'frame', win.epath) + end def frame - tk_call_without_enc('wm', 'frame', path) + Wm.frame(self) end + alias wm_frame frame - def geometry(geom=nil) + def Wm.geometry(win, geom=nil) if geom - tk_call_without_enc('wm', 'geometry', path, geom) - self + tk_call_without_enc('wm', 'geometry', win.epath, geom) + win else - tk_call_without_enc('wm', 'geometry', path) + tk_call_without_enc('wm', 'geometry', win.epath) end end + def geometry(geom=nil) + Wm.geometry(self, geom) + end + alias wm_geometry geometry TOPLEVEL_METHODCALL_OPTKEYS['geometry'] = 'geometry' - def wm_grid(*args) + def Wm.grid(win, *args) if args.size == 0 - list(tk_call_without_enc('wm', 'grid', path)) + list(tk_call_without_enc('wm', 'grid', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call_without_enc('wm', 'grid', path, *args) - self + tk_call_without_enc('wm', 'grid', win.epath, *args) + win end end + def wm_grid(*args) + Wm.grid(self, *args) + end TOPLEVEL_METHODCALL_OPTKEYS['wm_grid'] = 'wm_grid' - def group(leader = nil) + def Wm.group(win, leader = nil) if leader - tk_call('wm', 'group', path, leader) - self + tk_call('wm', 'group', win.epath, leader) + win else - window(tk_call('wm', 'group', path)) + window(tk_call('wm', 'group', win.epath)) end end + def group(leader = nil) + Wm.group(self, leader) + end + alias wm_group group TOPLEVEL_METHODCALL_OPTKEYS['group'] = 'group' - def iconbitmap(bmp=nil) + def Wm.iconbitmap(win, bmp=nil) if bmp - tk_call_without_enc('wm', 'iconbitmap', path, bmp) - self + tk_call_without_enc('wm', 'iconbitmap', win.epath, bmp) + win else - image_obj(tk_call_without_enc('wm', 'iconbitmap', path)) + image_obj(tk_call_without_enc('wm', 'iconbitmap', win.epath)) end end + def iconbitmap(bmp=nil) + Wm.iconbitmap(self, bmp) + end + alias wm_iconbitmap iconbitmap TOPLEVEL_METHODCALL_OPTKEYS['iconbitmap'] = 'iconbitmap' - def iconphoto(*imgs) + def Wm.iconphoto(win, *imgs) if imgs.empty? - @wm_iconphoto = nil unless defined? @wm_iconphoto - return @wm_iconphoto + win.instance_eval{ + @wm_iconphoto = nil unless defined? @wm_iconphoto + return @wm_iconphoto + } end imgs = imgs[0] if imgs.length == 1 && imgs[0].kind_of?(Array) - tk_call_without_enc('wm', 'iconphoto', path, *imgs) - @wm_iconphoto = imgs - self + tk_call_without_enc('wm', 'iconphoto', win.epath, *imgs) + win.instance_eval{ @wm_iconphoto = imgs } + win + end + def iconphoto(*imgs) + Wm.iconphoto(self, *imgs) end + alias wm_iconphoto iconphoto TOPLEVEL_METHODCALL_OPTKEYS['iconphoto'] = 'iconphoto' - def iconphoto_default(*imgs) + def Wm.iconphoto_default(win, *imgs) imgs = imgs[0] if imgs.length == 1 && imgs[0].kind_of?(Array) - tk_call_without_enc('wm', 'iconphoto', path, '-default', *imgs) - self + tk_call_without_enc('wm', 'iconphoto', win.epath, '-default', *imgs) + win + end + def iconphoto_default(*imgs) + Wm.iconphoto_default(self, *imgs) end + alias wm_iconphoto_default iconphoto_default - def iconify(ex = true) + def Wm.iconify(win, ex = true) if ex - tk_call_without_enc('wm', 'iconify', path) + tk_call_without_enc('wm', 'iconify', win.epath) else - self.deiconify + Wm.deiconify(win) end - self + win + end + def iconify(ex = true) + Wm.iconify(self, ex) end + alias wm_iconify iconify - def iconmask(bmp=nil) + def Wm.iconmask(win, bmp=nil) if bmp - tk_call_without_enc('wm', 'iconmask', path, bmp) - self + tk_call_without_enc('wm', 'iconmask', win.epath, bmp) + win else - image_obj(tk_call_without_enc('wm', 'iconmask', path)) + image_obj(tk_call_without_enc('wm', 'iconmask', win.epath)) end end + def iconmask(bmp=nil) + Wm.iconmask(self, bmp) + end + alias wm_iconmask iconmask TOPLEVEL_METHODCALL_OPTKEYS['iconmask'] = 'iconmask' - def iconname(name=nil) + def Wm.iconname(win, name=nil) if name - tk_call('wm', 'iconname', path, name) - self + tk_call('wm', 'iconname', win.epath, name) + win else - tk_call('wm', 'iconname', path) + tk_call('wm', 'iconname', win.epath) end end + def iconname(name=nil) + Wm.iconname(self, name) + end + alias wm_iconname iconname TOPLEVEL_METHODCALL_OPTKEYS['iconname'] = 'iconname' - def iconposition(*args) + def Wm.iconposition(win, *args) if args.size == 0 - list(tk_call_without_enc('wm', 'iconposition', path)) + list(tk_call_without_enc('wm', 'iconposition', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call_without_enc('wm', 'iconposition', path, *args) - self + tk_call_without_enc('wm', 'iconposition', win.epath, *args) + win end end + def iconposition(*args) + Wm.iconposition(self, *args) + end + alias wm_iconposition iconposition TOPLEVEL_METHODCALL_OPTKEYS['iconposition'] = 'iconposition' - def iconwindow(win = nil) - if win - tk_call_without_enc('wm', 'iconwindow', path, win) - self + def Wm.iconwindow(win, iconwin = nil) + if iconwin + tk_call_without_enc('wm', 'iconwindow', win.epath, iconwin) + win else - w = tk_call_without_enc('wm', 'iconwindow', path) + w = tk_call_without_enc('wm', 'iconwindow', win.epath) (w == '')? nil: window(w) end end + def iconwindow(iconwin = nil) + Wm.iconwindow(self, iconwin) + end + alias wm_iconwindow iconwindow TOPLEVEL_METHODCALL_OPTKEYS['iconwindow'] = 'iconwindow' - def maxsize(*args) + def Wm.manage(win) + # Tcl/Tk 8.5+ feature + tk_call_without_enc('wm', 'manage', win.epath) + win + end + def wm_manage + Wm.manage(self) + end +=begin + def Wm.manage(win, use_id = nil) + # Tcl/Tk 8.5+ feature + # -------------------------------------------------------------- + # In the future release, I want to support to embed the 'win' + # into the container which has window-id 'use-id'. + # It may give users frexibility on controlling their GUI. + # However, it may be difficult for current Tcl/Tk (Tcl/Tk8.5.1), + # because it seems to require to modify Tcl/Tk's source code. + # -------------------------------------------------------------- + if use_id + tk_call_without_enc('wm', 'manage', win.epath, '-use', use_id) + else + tk_call_without_enc('wm', 'manage', win.epath) + end + win + end +=end + + def Wm.maxsize(win, *args) if args.size == 0 - list(tk_call_without_enc('wm', 'maxsize', path)) + list(tk_call_without_enc('wm', 'maxsize', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call_without_enc('wm', 'maxsize', path, *args) - self + tk_call_without_enc('wm', 'maxsize', win.epath, *args) + win end end + def maxsize(*args) + Wm.maxsize(self, *args) + end + alias wm_maxsize maxsize TOPLEVEL_METHODCALL_OPTKEYS['maxsize'] = 'maxsize' - def minsize(*args) + def Wm.minsize(win, *args) if args.size == 0 - list(tk_call_without_enc('wm', 'minsize', path)) + list(tk_call_without_enc('wm', 'minsize', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call_without_enc('wm', 'minsize', path, *args) - self + tk_call_without_enc('wm', 'minsize', win.path, *args) + win end end + def minsize(*args) + Wm.minsize(self, *args) + end + alias wm_minsize minsize TOPLEVEL_METHODCALL_OPTKEYS['minsize'] = 'minsize' - def overrideredirect(mode=None) - if mode == None - bool(tk_call_without_enc('wm', 'overrideredirect', path)) + def Wm.overrideredirect(win, mode=TkComm::None) + if mode == TkComm::None + bool(tk_call_without_enc('wm', 'overrideredirect', win.epath)) else - tk_call_without_enc('wm', 'overrideredirect', path, mode) - self + tk_call_without_enc('wm', 'overrideredirect', win.epath, mode) + win end end + def overrideredirect(mode=TkComm::None) + Wm.overrideredirect(self, mode=TkComm::None) + end + alias wm_overrideredirect overrideredirect TOPLEVEL_METHODCALL_OPTKEYS['overrideredirect'] = 'overrideredirect' - def positionfrom(who=None) - if who == None - r = tk_call_without_enc('wm', 'positionfrom', path) + def Wm.positionfrom(win, who=TkComm::None) + if who == TkComm::None + r = tk_call_without_enc('wm', 'positionfrom', win.epath) (r == "")? nil: r else - tk_call_without_enc('wm', 'positionfrom', path, who) - self + tk_call_without_enc('wm', 'positionfrom', win.epath, who) + win end end + def positionfrom(who=TkComm::None) + Wm.positionfrom(self, who) + end + alias wm_positionfrom positionfrom TOPLEVEL_METHODCALL_OPTKEYS['positionfrom'] = 'positionfrom' - def protocol(name=nil, cmd=nil, &b) + def Wm.protocol(win, name=nil, cmd=nil, &b) if cmd - tk_call_without_enc('wm', 'protocol', path, name, cmd) - self + tk_call_without_enc('wm', 'protocol', win.epath, name, cmd) + win elsif b - tk_call_without_enc('wm', 'protocol', path, name, proc(&b)) - self + tk_call_without_enc('wm', 'protocol', win.epath, name, proc(&b)) + win elsif name - result = tk_call_without_enc('wm', 'protocol', path, name) + result = tk_call_without_enc('wm', 'protocol', win.epath, name) (result == "")? nil : tk_tcl2ruby(result) else - tk_split_simplelist(tk_call_without_enc('wm', 'protocol', path)) + tk_split_simplelist(tk_call_without_enc('wm', 'protocol', win.epath)) end end + def protocol(name=nil, cmd=nil, &b) + Wm.protocol(self, name, cmd, &b) + end + alias wm_protocol protocol - def protocols(kv=nil) + def Wm.protocols(win, kv=nil) unless kv ret = {} - self.protocol.each{|name| - ret[name] = self.protocol(name) + Wm.protocol(win).each{|name| + ret[name] = Wm.protocol(win, name) } return ret end @@ -279,82 +413,140 @@ module Tk unless kv.kind_of?(Hash) fail ArgumentError, 'expect a hash of protocol=>command' end - kv.each{|k, v| self.protocol(k, v)} - self + kv.each{|k, v| Wm.protocol(win, k, v)} + win end + def protocols(kv=nil) + Wm.protocols(self, kv) + end + alias wm_protocols protocols TOPLEVEL_METHODCALL_OPTKEYS['protocols'] = 'protocols' - def resizable(*args) + def Wm.resizable(win, *args) if args.length == 0 - list(tk_call_without_enc('wm', 'resizable', path)).collect{|e| bool(e)} + list(tk_call_without_enc('wm', 'resizable', win.epath)).map!{|e| bool(e)} else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call_without_enc('wm', 'resizable', path, *args) - self + tk_call_without_enc('wm', 'resizable', win.epath, *args) + win end end + def resizable(*args) + Wm.resizable(self, *args) + end + alias wm_resizable resizable TOPLEVEL_METHODCALL_OPTKEYS['resizable'] = 'resizable' - def sizefrom(who=None) - if who == None - r = tk_call_without_enc('wm', 'sizefrom', path) + def Wm.sizefrom(win, who=TkComm::None) + if who == TkComm::None + r = tk_call_without_enc('wm', 'sizefrom', win.epath) (r == "")? nil: r else - tk_call_without_enc('wm', 'sizefrom', path, who) - self + tk_call_without_enc('wm', 'sizefrom', win.epath, who) + win end end + def sizefrom(who=TkComm::None) + Wm.sizefrom(self, who) + end + alias wm_sizefrom sizefrom TOPLEVEL_METHODCALL_OPTKEYS['sizefrom'] = 'sizefrom' + def Wm.stackorder(win) + list(tk_call('wm', 'stackorder', win.epath)) + end def stackorder - list(tk_call('wm', 'stackorder', path)) + Wm.stackorder(self) end + alias wm_stackorder stackorder - def stackorder_isabove(win) - bool(tk_call('wm', 'stackorder', path, 'isabove', win)) + def Wm.stackorder_isabove(win, target) + bool(tk_call('wm', 'stackorder', win.epath, 'isabove', target)) + end + def Wm.stackorder_is_above(win, target) + Wm.stackorder_isabove(win, target) + end + def stackorder_isabove(target) + Wm.stackorder_isabove(self, target) end + alias stackorder_is_above stackorder_isabove + alias wm_stackorder_isabove stackorder_isabove + alias wm_stackorder_is_above stackorder_isabove - def stackorder_isbelow(win) - bool(tk_call('wm', 'stackorder', path, 'isbelow', win)) + def Wm.stackorder_isbelow(win, target) + bool(tk_call('wm', 'stackorder', win.epath, 'isbelow', target)) end + def Wm.stackorder_is_below(win, target) + Wm.stackorder_isbelow(win, target) + end + def stackorder_isbelow(target) + Wm.stackorder_isbelow(self, target) + end + alias stackorder_is_below stackorder_isbelow + alias wm_stackorder_isbelow stackorder_isbelow + alias wm_stackorder_is_below stackorder_isbelow - def state(st=nil) + def Wm.state(win, st=nil) if st - tk_call_without_enc('wm', 'state', path, st) - self + tk_call_without_enc('wm', 'state', win.epath, st) + win else - tk_call_without_enc('wm', 'state', path) + tk_call_without_enc('wm', 'state', win.epath) end end + def state(st=nil) + Wm.state(self, st) + end + alias wm_state state TOPLEVEL_METHODCALL_OPTKEYS['state'] = 'state' - def title(str=nil) + def Wm.title(win, str=nil) if str - tk_call('wm', 'title', path, str) - self + tk_call('wm', 'title', win.epath, str) + win else - tk_call('wm', 'title', path) + tk_call('wm', 'title', win.epath) end end + def title(str=nil) + Wm.title(self, str) + end + alias wm_title title TOPLEVEL_METHODCALL_OPTKEYS['title'] = 'title' - def transient(master=nil) + def Wm.transient(win, master=nil) if master - tk_call_without_enc('wm', 'transient', path, master) - self + tk_call_without_enc('wm', 'transient', win.epath, master) + win else - window(tk_call_without_enc('wm', 'transient', path)) + window(tk_call_without_enc('wm', 'transient', win.epath)) end end + def transient(master=nil) + Wm.transient(self, master) + end + alias wm_transient transient TOPLEVEL_METHODCALL_OPTKEYS['transient'] = 'transient' - def withdraw(ex = true) + def Wm.withdraw(win, ex = true) if ex - tk_call_without_enc('wm', 'withdraw', path) + tk_call_without_enc('wm', 'withdraw', win.epath) else - self.deiconify + Wm.deiconify(win) end - self + win end + def withdraw(ex = true) + Wm.withdraw(self, ex) + end + alias wm_withdraw withdraw + end + + module Wm_for_General + Wm.instance_methods.each{|m| + if (m = m.to_s) =~ /^wm_(.*)$/ + eval "def #{m}(*args); Tk::Wm.#{$1}(self, *args); end" + end + } end end diff --git a/ext/tk/lib/tkextlib/SUPPORT_STATUS b/ext/tk/lib/tkextlib/SUPPORT_STATUS index 15925cba7..cfbe274c8 100644 --- a/ext/tk/lib/tkextlib/SUPPORT_STATUS +++ b/ext/tk/lib/tkextlib/SUPPORT_STATUS @@ -83,7 +83,7 @@ BLT 2.4z http://sourceforge.net/projects/blt TkTreeCtrl CVS/Hd(2005-12-02) http://sourceforge.net/projects/tktreectrl ==> treectrl -Tile 0.7.8 +Tile 0.8.0/8.5.1 http://sourceforge.net/projects/tktable ==> tile diff --git a/ext/tk/lib/tkextlib/blt/bitmap.rb b/ext/tk/lib/tkextlib/blt/bitmap.rb index 31cf8d422..23c6d2d06 100644 --- a/ext/tk/lib/tkextlib/blt/bitmap.rb +++ b/ext/tk/lib/tkextlib/blt/bitmap.rb @@ -13,7 +13,16 @@ module Tk::BLT TkCommandNames = ['::blt::bitmap'.freeze].freeze BITMAP_ID_TBL = TkCore::INTERP.create_table - BITMAP_ID = ['blt_bitmap_id'.freeze, '00000'.taint].freeze + + (BITMAP_ID = ['blt_bitmap_id'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + BITMAP_ID_TBL.mutex.synchronize{ BITMAP_ID_TBL.clear } + } def self.data(name) dat = tk_simple_list(tk_call('::blt::bitmap', 'data', name)) @@ -64,9 +73,13 @@ module Tk::BLT if name @id = name else - @id = BITMAP_ID.join(TkCore::INTERP._ip_id_) - BITMAP_ID[1].succ! - BITMAP_ID_TBL[@id] = self + BITMAP_ID.mutex.synchronize{ + @id = BITMAP_ID.join(TkCore::INTERP._ip_id_) + BITMAP_ID[1].succ! + } + BITMAP_ID_TBL.mutex.synchronize{ + BITMAP_ID_TBL[@id] = self + } end @path = @id diff --git a/ext/tk/lib/tkextlib/blt/component.rb b/ext/tk/lib/tkextlib/blt/component.rb index ad78a5430..dd387634e 100644 --- a/ext/tk/lib/tkextlib/blt/component.rb +++ b/ext/tk/lib/tkextlib/blt/component.rb @@ -327,13 +327,24 @@ module Tk::BLT ################# class Axis < TkObject - OBJ_ID = ['blt_chart_axis'.freeze, '00000'.taint].freeze - OBJ_TBL={} + (OBJ_ID = ['blt_chart_axis'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + AxisID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + AxisID_TBL.mutex.synchronize{ AxisID_TBL.clear } + } def self.id2obj(chart, id) cpath = chart.path - return id unless OBJ_TBL[cpath] - OBJ_TBL[cpath][id]? OBJ_TBL[cpath][id]: id + AxisID_TBL.mutex.synchronize{ + return id unless AxisID_TBL[cpath] + AxisID_TBL[cpath][id]? AxisID_TBL[cpath][id]: id + } end def self.new(chart, axis=nil, keys={}) @@ -341,12 +352,48 @@ module Tk::BLT keys = axis axis = nil end - OBJ_TBL[chart.path] = {} unless OBJ_TBL[chart.path] - return OBJ_TBL[chart.path][axis] if axis && OBJ_TBL[chart.path][axis] - super(chart, axis, keys) + if keys + keys = _symbolkey2str(keys) + not_create = keys.delete('without_creating') + else + not_create = false + end + + obj = nil + AxisID_TBL.mutex.synchronize{ + chart_path = chart.path + AxisID_TBL[chart_path] ||= {} + if axis && AxisID_TBL[chart_path][axis] + obj = AxisID_TBL[chart_path][axis] + else + (obj = self.allocate).instance_eval{ + if axis + @axis = @id = axis.to_s + else + OBJ_ID.mutex.synchronize{ + @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } + end + @path = @id + @parent = @chart = chart + @cpath = @chart.path + Axis::AxisID_TBL[@cpath][@axis] = self + unless not_create + tk_call(@chart, 'axis', 'create', @axis, keys) + return obj + end + } + end + } + + obj.configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, axis=nil, keys={}) + # dummy:: not called by 'new' method + if axis.kind_of?(Hash) keys = axis axis = nil @@ -354,13 +401,15 @@ module Tk::BLT if axis @axis = @id = axis.to_s else - @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze - OBJ_ID[1].succ! + OBJ_ID.mutex.synchronize{ + @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } end @path = @id @parent = @chart = chart @cpath = @chart.path - Axis::OBJ_TBL[@cpath][@axis] = self + # Axis::AxisID_TBL[@cpath][@axis] = self keys = _symbolkey2str(keys) unless keys.delete('without_creating') # @chart.axis_create(@axis, keys) @@ -438,17 +487,34 @@ module Tk::BLT ################# class Crosshairs < TkObject - OBJ_TBL={} + CrosshairsID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + CrosshairsID_TBL.mutex.synchronize{ CrosshairsID_TBL.clear } + } def self.new(chart, keys={}) - return OBJ_TBL[chart.path] if OBJ_TBL[chart.path] - super(chart, keys) + obj = nil + CrosshairsID_TBL.mutex.synchronize{ + unless (obj = CrosshairsID_TBL[chart.path]) + (obj = self.allocate).instance_eval{ + @parent = @chart = chart + @cpath = @chart.path + @path = @id = 'crosshairs' + Crosshairs::CrosshairsID_TBL[@cpath] = self + } + end + } + chart.crosshair_configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, keys={}) + # dummy:: not called by 'new' method + @parent = @chart = chart @cpath = @chart.path - Crosshairs::OBJ_TBL[@cpath] = self + # Crosshairs::CrosshairsID_TBL[@cpath] = self @chart.crosshair_configure(keys) unless keys.empty? @path = @id = 'crosshairs' end @@ -500,12 +566,18 @@ module Tk::BLT ElementTypeName = 'element' ElementTypeToClass = { ElementTypeName=>self } + ElementID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ ElementID_TBL.clear } + TkCore::INTERP.init_ip_env{ + ElementID_TBL.mutex.synchronize{ ElementID_TBL.clear } + } - OBJ_ID = ['blt_chart_element'.freeze, '00000'.taint].freeze - OBJ_TBL={} + (OBJ_ID = ['blt_chart_element'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } def Element.type2class(type) ElementTypeToClass[type] @@ -513,8 +585,10 @@ module Tk::BLT def Element.id2obj(chart, id) cpath = chart.path - return id unless OBJ_TBL[cpath] - OBJ_TBL[cpath][id]? OBJ_TBL[cpath][id]: id + ElementID_TBL.mutex.synchronize{ + return id unless ElementID_TBL[cpath] + ElementID_TBL[cpath][id]? ElementID_TBL[cpath][id]: id + } end def self.new(chart, element=nil, keys={}) @@ -522,14 +596,49 @@ module Tk::BLT keys = element element = nil end - OBJ_TBL[chart.path] = {} unless OBJ_TBL[chart.path] - if element && OBJ_TBL[chart.path][element] - return OBJ_TBL[chart.path][element] + if keys + keys = _symbolkey2str(keys) + not_create = keys.delete('without_creating') + else + not_create = false end - super(chart, element, keys) + + obj = nil + ElementID_TBL.mutex.synchronize{ + chart_path = chart.path + ElementID_TBL[chart_path] ||= {} + if element && ElementID_TBL[chart_path][element] + obj = ElementID_TBL[chart_path][element] + else + (obj = self.allocate).instance_eval{ + if element + @element = @id = element.to_s + else + OBJ_ID.mutex.synchronize{ + @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } + end + @path = @id + @parent = @chart = chart + @cpath = @chart.path + @typename = self.class::ElementTypeName + Element::ElementID_TBL[@cpath][@element] = self + unless not_create + tk_call(@chart, @typename, 'create', @element, keys) + return obj + end + } + end + } + + obj.configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, element=nil, keys={}) + # dummy:: not called by 'new' method + if element.kind_of?(Hash) keys = element element = nil @@ -537,14 +646,16 @@ module Tk::BLT if element @element = @id = element.to_s else - @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze - OBJ_ID[1].succ! + OBJ_ID.mutex.synchronize{ + @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } end @path = @id @parent = @chart = chart @cpath = @chart.path @typename = self.class::ElementTypeName - Element::OBJ_TBL[@cpath][@element] = self + # Element::ElementID_TBL[@cpath][@element] = self keys = _symbolkey2str(keys) unless keys.delete('without_creating') # @chart.element_create(@element, keys) @@ -622,17 +733,33 @@ module Tk::BLT ################# class GridLine < TkObject - OBJ_TBL={} + GridLineID_TBL = TkCore::INTERP.create_table + TkCore::INTERP.init_ip_env{ + GridLineID_TBL.mutex.synchronize{ GridLineID_TBL.clear } + } def self.new(chart, keys={}) - return OBJ_TBL[chart.path] if OBJ_TBL[chart.path] - super(chart, keys) + obj = nil + GridLineID_TBL.mutex.synchronize{ + unless (obj = GridLineID_TBL[chart.path]) + (obj = self.allocate).instance_eval{ + @parent = @chart = chart + @cpath = @chart.path + @path = @id = 'grid' + GridLine::GridLineID_TBL[@cpath] = self + } + end + } + chart.gridline_configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, keys={}) + # dummy:: not called by 'new' method + @parent = @chart = chart @cpath = @chart.path - GridLine::OBJ_TBL[@cpath] = self + # GridLine::GridLineID_TBL[@cpath] = self @chart.gridline_configure(keys) unless keys.empty? @path = @id = 'grid' end @@ -676,18 +803,35 @@ module Tk::BLT ################# class Legend < TkObject - OBJ_TBL={} + LegendID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + LegendID_TBL.mutex.synchronize{ LegendID_TBL.clear } + } def self.new(chart, keys={}) - return OBJ_TBL[chart.path] if OBJ_TBL[chart.path] - super(chart, keys) + obj = nil + LegenedID_TBL.mutex.synchronize{ + unless (obj = LegenedID_TBL[chart.path]) + (obj = self.allocate).instance_eval{ + @parent = @chart = chart + @cpath = @chart.path + @path = @id = 'crosshairs' + Legend::LegenedID_TBL[@cpath] = self + } + end + } + chart.legend_configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, keys={}) + # dummy:: not called by 'new' method + @parent = @chart = chart @cpath = @chart.path - Crosshairs::OBJ_TBL[@cpath] = self - @chart.crosshair_configure(keys) unless keys.empty? + # Legend::LegendID_TBL[@cpath] = self + @chart.legend_configure(keys) unless keys.empty? @path = @id = 'legend' end @@ -729,13 +873,24 @@ module Tk::BLT ################# class Pen < TkObject - OBJ_ID = ['blt_chart_pen'.freeze, '00000'.taint].freeze - OBJ_TBL={} + (OBJ_ID = ['blt_chart_pen'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + PenID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + PenID_TBL.mutex.synchronize{ PenID_TBL.clear } + } def self.id2obj(chart, id) cpath = chart.path - return id unless OBJ_TBL[cpath] - OBJ_TBL[cpath][id]? OBJ_TBL[cpath][id]: id + PenID_TBL.mutex.synchronize{ + return id unless PenID_TBL[cpath] + PenID_TBL[cpath][id]? PenID_TBL[cpath][id]: id + } end def self.new(chart, pen=nil, keys={}) @@ -743,9 +898,43 @@ module Tk::BLT keys = pen pen = nil end - OBJ_TBL[chart.path] = {} unless OBJ_TBL[chart.path] - return OBJ_TBL[chart.path][pen] if pen && OBJ_TBL[chart.path][pen] - super(chart, pen, keys) + if keys + keys = _symbolkey2str(keys) + not_create = keys.delete('without_creating') + else + not_create = false + end + + obj = nil + PenID_TBL.mutex.synchronize{ + chart_path = chart.path + PenID_TBL[chart_path] ||= {} + if pen && PenID_TBL[chart_path][pen] + obj = PenID_TBL[chart_path][pen] + else + (obj = self.allocate).instance_eval{ + if pen + @pen = @id = pen.to_s + else + OBJ_ID.mutex.synchronize{ + @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } + end + @path = @id + @parent = @chart = chart + @cpath = @chart.path + Pen::PenID_TBL[@cpath][@pen] = self + unless not_create + tk_call(@chart, 'pen', 'create', @pen, keys) + return obj + end + } + end + } + + obj.configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, pen=nil, keys={}) @@ -756,13 +945,15 @@ module Tk::BLT if pen @pen = @id = pen.to_s else - @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze - OBJ_ID[1].succ! + OBJ_ID.mutex.synchronize{ + @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } end @path = @id @parent = @chart = chart @cpath = @chart.path - Pen::OBJ_TBL[@cpath][@pen] = self + Pen::PenID_TBL[@cpath][@pen] = self keys = _symbolkey2str(keys) unless keys.delete('without_creating') # @chart.pen_create(@pen, keys) @@ -805,17 +996,34 @@ module Tk::BLT ################# class Postscript < TkObject - OBJ_TBL={} + PostscriptID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + PostscriptID_TBL.mutex.synchronize{ PostscriptID_TBL.clear } + } def self.new(chart, keys={}) - return OBJ_TBL[chart.path] if OBJ_TBL[chart.path] - super(chart, keys) + obj = nil + PostscriptID_TBL.mutex.synchronize{ + unless (obj = PostscriptID_TBL[chart.path]) + (obj = self.allocate).instance_eval{ + @parent = @chart = chart + @cpath = @chart.path + @path = @id = 'postscript' + Postscript::PostscriptID_TBL[@cpath] = self + } + end + } + chart.postscript_configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, keys={}) + # dummy:: not called by 'new' method + @parent = @chart = chart @cpath = @chart.path - Postscript::OBJ_TBL[@cpath] = self + # Postscript::PostscriptID_TBL[@cpath] = self @chart.postscript_configure(keys) unless keys.empty? @path = @id = 'postscript' end @@ -870,7 +1078,9 @@ module Tk::BLT MarkerTypeToClass = {} MarkerID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ MarkerID_TBL.clear } + TkCore::INTERP.init_ip_env{ + MarkerID_TBL.mutex.synchronize{ MarkerID_TBL.clear } + } def Marker.type2class(type) MarkerTypeToClass[type] @@ -878,8 +1088,13 @@ module Tk::BLT def Marker.id2obj(chart, id) cpath = chart.path - return id unless MarkerID_TBL[cpath] - MarkerID_TBL[cpath][id]? MarkerID_TBL[cpath][id]: id + MarkerID_TBL.mutex.synchronize{ + if MarkerID_TBL[cpath] + MarkerID_TBL[cpath][id]? MarkerID_TBL[cpath][id]: id + else + id + end + } end def self._parse_create_args(keys) @@ -943,10 +1158,10 @@ module Tk::BLT @parent = @chart = chart @cpath = chart.path @id = id - unless Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] - Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] = {} - end - Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self + Tk::BLT::PlotComponent::Marker::MarkerID_TBL.mutex.synchronize{ + Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] ||= {} + Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self + } } obj end @@ -956,10 +1171,10 @@ module Tk::BLT @cpath = parent.path @path = @id = create_self(*args) # an integer number as 'item id' - unless Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] - Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] = {} - end - Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self + Tk::BLT::PlotComponent::Marker::MarkerID_TBL.mutex.synchronize{ + Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] ||= {} + Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self + } end def create_self(*args) self.class.create(@chart, *args) # return an integer as 'item id' @@ -1037,14 +1252,14 @@ module Tk::BLT ################# def __destroy_hook__ - Axis::OBJ_TBL.delete(@path) - Crosshairs::OBJ_TBL.delete(@path) - Element::OBJ_TBL.delete(@path) - GridLine::OBJ_TBL.delete(@path) - Legend::OBJ_TBL.delete(@path) - Pen::OBJ_TBL.delete(@path) - Postscript::OBJ_TBL.delete(@path) - Marker::OBJ_TBL.delete(@path) + Axis::AxisID_TBL.delete(@path) + Crosshairs::CrosshairsID_TBL.delete(@path) + Element::ElementID_TBL.delete(@path) + GridLine::GridLineID_TBL.delete(@path) + Legend::LegendID_TBL.delete(@path) + Pen::PenID_TBL.delete(@path) + Postscript::PostscriptID_TBL.delete(@path) + Marker::MarkerID_TBL.delete(@path) super() end diff --git a/ext/tk/lib/tkextlib/blt/dragdrop.rb b/ext/tk/lib/tkextlib/blt/dragdrop.rb index 68fb9e591..98b1a4832 100644 --- a/ext/tk/lib/tkextlib/blt/dragdrop.rb +++ b/ext/tk/lib/tkextlib/blt/dragdrop.rb @@ -81,6 +81,22 @@ module Tk::BLT nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL) def self.ret_val(val) @@ -107,6 +123,22 @@ module Tk::BLT nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL) def self.ret_val(val) @@ -145,6 +177,22 @@ module Tk::BLT nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL) end diff --git a/ext/tk/lib/tkextlib/blt/tabset.rb b/ext/tk/lib/tkextlib/blt/tabset.rb index c26b6ee00..1a0f312c4 100644 --- a/ext/tk/lib/tkextlib/blt/tabset.rb +++ b/ext/tk/lib/tkextlib/blt/tabset.rb @@ -12,14 +12,26 @@ module Tk::BLT include TkTreatItemFont TabID_TBL = TkCore::INTERP.create_table - TabsetTab_ID = ['blt_tabset_tab'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TabID_TBL.clear } + (TabsetTab_ID = ['blt_tabset_tab'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + TabID_TBL.mutex.synchronize{ TabID_TBL.clear } + } def self.id2obj(tabset, id) tpath = tabset.path - return id unless TabID_TBL[tpath] - TabID_TBL[tpath][id]? TabID_TBL[tpath]: id + TabID_TBL.mutex.synchronize{ + if TabID_TBL[tpath] + TabID_TBL[tpath][id]? TabID_TBL[tpath]: id + else + id + end + } end def self.new(parent, pos=nil, name=nil, keys={}) @@ -32,12 +44,20 @@ module Tk::BLT keys = name name = nil end - - if name && TabID_TBL[parent.path] && TabID_TBL[parent.path][name] - TabID_TBL[parent.path][name] - else - super(parent, pos, name, keys) - end + obj = nil + TabID_TBL.mutex.synchronize{ + if name && TabID_TBL[parent.path] && TabID_TBL[parent.path][name] + obj = TabID_TBL[parent.path][name] + obj.configure if keys && ! keys.empty? + else + (obj = self.allocate).instance_eval{ + initialize(parent, pos, name, keys) + TabID_TBL[@tpath] = {} unless TabID_TBL[@tpath] + TabID_TBL[@tpath][@id] = self + } + end + } + obj end def initialize(parent, pos, name, keys) @@ -45,9 +65,6 @@ module Tk::BLT @tpath = parent.path if name @path = @id = name - TabID_TBL[@tpath] = {} unless TabID_TBL[@tpath] - TabID_TBL[@tpath][@id] = self - unless (list(tk_call(@tpath, 'tab', 'names', @id)).empty?) if pos idx = tk_call(@tpath, 'index', '-name', @id) @@ -58,18 +75,18 @@ module Tk::BLT end end tk_call(@tpath, 'tab', 'configure', @id, keys) - return + else + pos = 'end' unless pos + tk_call(@tpath, 'insert', pos, @id, keys) end - else - @path = @id = TabsetTab_ID.join(TkCore::INTERP._ip_id_) - TabID_TBL[@tpath] = {} unless TabID_TBL[@tpath] - TabID_TBL[@tpath][@id] = self - TabsetTab_ID[1].succ! + TabsetTab_ID.mutex.synchronize{ + @path = @id = TabsetTab_ID.join(TkCore::INTERP._ip_id_) + TabsetTab_ID[1].succ! + } + pos = 'end' unless pos + tk_call(@tpath, 'insert', pos, @id, keys) end - - pos = 'end' unless pos - tk_call(@tpath, 'insert', pos, @id, keys) end #def bind(context, cmd=Proc.new, *args) @@ -123,7 +140,9 @@ module Tk::BLT def delete() @t.delete(@id) - TabID_TBL[@tpath].delete(@id) + TabID_TBL.mutex.synchronize{ + TabID_TBL[@tpath].delete(@id) + } self end @@ -184,7 +203,9 @@ module Tk::BLT WidgetClassNames[WidgetClassName] = self def __destroy_hook__ - Tk::BLT::Tabset::Tab::TabID_TBL.delete(@path) + Tk::BLT::Tabset::Tab::TabID_TBL.mutex.synchronize{ + Tk::BLT::Tabset::Tab::TabID_TBL.delete(@path) + } end ######################################## @@ -291,11 +312,15 @@ module Tk::BLT def delete(first, last=None) tk_send('delete', tagindex(first), tagindex(last)) if first.kind_of?(Tk::BLT::Tabset::Tab) - TabID_TBL[@path].delete(first.id) + TabID_TBL.mutex.synchronize{ + TabID_TBL[@path].delete(first.id) + } end # middle tabs of the range are unknown if last.kind_of?(Tk::BLT::Tabset::Tab) - TabID_TBL[@path].delete(last.id) + TabID_TBL.mutex.synchronize{ + TabID_TBL[@path].delete(last.id) + } end self end diff --git a/ext/tk/lib/tkextlib/blt/tree.rb b/ext/tk/lib/tkextlib/blt/tree.rb index 07dc7ef7e..77b85f171 100644 --- a/ext/tk/lib/tkextlib/blt/tree.rb +++ b/ext/tk/lib/tkextlib/blt/tree.rb @@ -12,53 +12,77 @@ module Tk::BLT ################################### - class Node < TkObject + class Node < TkObject TreeNodeID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ TreeNodeID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + TreeNodeID_TBL.mutex.synchronize{ TreeNodeID_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless TreeNodeID_TBL[tpath] - if TreeNodeID_TBL[tpath][id] - TreeNodeID_TBL[tpath][id] - else - begin - self.new(tree, nil, 'node'=>Integer(id)) - rescue + TreeNodeID_TBL.mutex.synchronize{ + if TreeNodeID_TBL[tpath] + if TreeNodeID_TBL[tpath][id] + TreeNodeID_TBL[tpath][id] + else + begin + # self.new(tree, nil, 'node'=>Integer(id)) + id = Integer(id) + if bool(tk_call(@tpath, 'exists', id)) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = tpath + @path = @id = id + TreeNodeID_TBL[@tpath] = {} unless TreeNodeID_TBL[@tpath] + TreeNodeID_TBL[@tpath][@id] = self + } + obj + else + id + end + rescue + id + end + end + else id end - end + } end def self.new(tree, parent, keys={}) keys = _symbolkey2str(keys) tpath = tree.path - if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id]) - keys.delete('node') - tk_call(tree.path, 'move', id, parent, keys) if parent - return obj - end + TreeNodeID_TBL.mutex.synchronize{ + TreeNodeID_TBL[tpath] ||= {} + if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id]) + keys.delete('node') + tk_call(tree.path, 'move', id, parent, keys) if parent + return obj + end - super(tree, parent, keys) + (obj = self.allocate).instance_eval{ + initialize(tree, parent, keys) + TreeNodeID_TBL[tpath][@id] = self + } + obj + } end def initialize(tree, parent, keys={}) @parent = @tree = tree @tpath = @parent.path - parent = tk_call(@tpath, 'root') unless parent - if (id = keys['node']) && bool(tk_call(@tpath, 'exists', id)) @path = @id = id keys.delete('node') tk_call(@tpath, 'move', @id, parent, keys) if parent else + parent = tk_call(@tpath, 'root') unless parent @path = @id = tk_call(@tpath, 'insert', parent, keys) end - - TreeNodeID_TBL[@tpath] = {} unless TreeNodeID_TBL[@tpath] - TreeNodeID_TBL[@tpath][@id] = self end def id @@ -243,17 +267,42 @@ module Tk::BLT class Tag < TkObject TreeTagID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ TreeTagID_TBL.clear } - TreeTag_ID = ['blt_tree_tag'.freeze, '00000'.taint].freeze + + TkCore::INTERP.init_ip_env{ + TreeTagID_TBL.mutex.synchronize{ TreeTagID_TBL.clear } + } + + (TreeTag_ID = ['blt_tree_tag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } def self.id2obj(tree, id) tpath = tree.path - return id unless TreeTagID_TBL[tpath] - if TreeTagID_TBL[tpath][id] - TreeTagID_TBL[tpath][id] - else - self.new(tree, id) - end + TreeTagID_TBL.mutex.synchronize{ + if TreeTagID_TBL[tpath] + if TreeTagID_TBL[tpath][id] + TreeTagID_TBL[tpath][id] + else + begin + # self.new(tree, id) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = id.dup.freeze if id + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } + obj + rescue + id + end + end + else + id + end + } end def initialize(tree, tag_str = nil) @@ -263,12 +312,15 @@ module Tk::BLT if tag_str @path = @id = tag_str.dup.freeze else - @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_) - TreeTagID_TBL[@id] = self - TreeTag_ID[1].succ! + TreeTag_ID.mutex.synchronize{ + @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_) + TreeTag_ID[1].succ! + } end - TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] - TreeTagID_TBL[@tpath][@id] = self + TreeTagID_TBL.mutex.synchronize{ + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } end def id @@ -287,7 +339,9 @@ module Tk::BLT def forget() tk_call(@tpath, 'tag', 'forget', @id) - TreeTagID_TBL[@tpath].delete(@id) + TreeTagID_TBL.mutex.synchronize{ + TreeTagID_TBL[@tpath].delete(@id) + } self end @@ -312,44 +366,63 @@ module Tk::BLT class Notify < TkObject NotifyID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ NotifyID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + NotifyID_TBL.mutex.synchronize{ NotifyID_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless NotifyID_TBL[tpath] - if NotifyID_TBL[tpath][id] - NotifyID_TBL[tpath][id] - else - begin - self.new([tree, id]) - rescue - id + NotifyID_TBL.mutex.synchronize{ + if NotifyID_TBL[tpath] + if NotifyID_TBL[tpath][id] + NotifyID_TBL[tpath][id] + else + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = id + NotifyID_TBL[@tpath] ||= {} + NotifyID_TBL[@tpath][@id] = self + } + obj + end + else + return id end - end + } end def self.new(tree, *args, &b) - if tree.kind_of?(Array) - # not create - if obj = NotifyID_TBL[tree[0].path][tree[1]] + NotifyID_TBL.mutex.synchronize{ + if tree.kind_of?(Array) + # not create + tpath = tree[0].path + NotifyID_TBL[tpath] ||= {} + unless (obj = NotifyID_TBL[tpath][tree[1]]) + (NotifyID_TBL[tpath][tree[1]] = + obj = self.allocate).instance_eval{ + @parent = @tree = tree[0] + @tpath = @parent.path + @path = @id = tree[1] + } + end return obj - else - return super(false, tree[0], tree[1]) end - end - super(true, tree, *args, &b) + (obj = self.allocate).instance_eval{ + initialize(tree, *args, &b) + NotifyID_TBL[@tpath] ||= {} + NotifyID_TBL[@tpath][@id] = self + } + return obj + } end - def initialize(create, tree, *args, &b) + def initialize(tree, *args, &b) @parent = @tree = tree @tpath = @parent.path - unless create - @path = @id = args[0] - return - end - # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) cmd = args.shift @@ -378,7 +451,9 @@ module Tk::BLT def delete() tk_call(@tpath, 'notify', 'delete', @id) - NotifyID_TBL[tpath].delete(@id) + NotifyID_TBL.mutex.synchronize{ + NotifyID_TBL[@tpath].delete(@id) + } self end @@ -395,44 +470,69 @@ module Tk::BLT class Trace < TkObject TraceID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ TraceID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + TraceID_TBL.mutex.synchronize{ TraceID_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless TraceID_TBL[tpath] - if TraceID_TBL[tpath][id] - TraceID_TBL[tpath][id] - else - begin - self.new([tree, id]) - rescue + TraceID_TBL.mutex.synchronize{ + if TraceID_TBL[tpath] + if TraceID_TBL[tpath][id] + TraceID_TBL[tpath][id] + else + begin + # self.new([tree, id]) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = node # == traceID + TraceID_TBL[@tpath] ||= {} + TraceID_TBL[@tpath][@id] = self + } + obj + rescue + id + end + end + else id end - end + } end def self.new(tree, *args, &b) - if tree.kind_of?(Array) - # not create - if obj = TraceID_TBL[tree[0].path][tree[1]] + TraceID_TBL.mutex.synchronize{ + if tree.kind_of?(Array) + # not create + tpath = tree[0].path + TraceID_TBL[tpath] ||= {} + unless (obj = TraceID_TBL[tpath][tree[1]]) + (TraceID_TBL[tpath][tree[1]] = + obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = tree[1] # == traceID + } + end return obj - else - return super(false, tree[0], tree[1]) end - end - super(true, tree, *args, &b) + # super(true, tree, *args, &b) + (obj = self.allocate).instance_eval{ + initialize(tree, *args, &b) + TraceID_TBL[@tpath] ||= {} + TraceID_TBL[@tpath][@id] = self + } + return obj + } end - def initialize(create, tree, node, key, opts, cmd=nil, &b) + def initialize(tree, node, key, opts, cmd=nil, &b) @parent = @tree = tree @tpath = @parent.path - unless create - @path = @id = node # == traceID - return - end - if !cmd if b cmd = Proc.new(&b) @@ -459,7 +559,9 @@ module Tk::BLT def delete() tk_call(@tpath, 'trace', 'delete', @id) - TraceID_TBL[tpath].delete(@id) + TraceID_TBL.mutex.synchronize{ + TraceID_TBL[tpath].delete(@id) + } self end @@ -475,7 +577,12 @@ module Tk::BLT ################################### TreeID_TBL = TkCore::INTERP.create_table - Tree_ID = ['blt_tree'.freeze, '00000'.taint].freeze + + (Tree_ID = ['blt_tree'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } def __keyonly_optkeys { @@ -498,7 +605,9 @@ module Tk::BLT end def self.id2obj(id) - TreeID_TBL[id]? TreeID_TBL[id]: id + TreeID_TBL.mutex.synchronize{ + TreeID_TBL[id]? TreeID_TBL[id]: id + } end def self.names(pat = None) @@ -513,27 +622,45 @@ module Tk::BLT end def self.new(name = nil) - return TreeID_TBL[name] if name && TreeID_TBL[name] - super(name) + TreeID_TBL.mutex.synchronize{ + if name && TreeID_TBL[name] + TreeID_TBL[name] + else + (obj = self.allocate).instance_eval{ + initialize(name) + TreeID_TBL[@id] = self + } + obj + end + } end def initialzie(name = nil) if name @path = @id = name else - @path = @id = Tree_ID.join(TkCore::INTERP._ip_id_) - TreeID_TBL[@id] = self - Tree_ID[1].succ! + Tree_ID.mutex.synchronize{ + @path = @id = Tree_ID.join(TkCore::INTERP._ip_id_) + Tree_ID[1].succ! + } end - TreeID_TBL[@id] = self + tk_call('::blt::tree', 'create', @id) end def __destroy_hook__ - Tk::BLT::Tree::Node::TreeNodeID_TBL.delete(@path) - Tk::BLT::Tree::Tag::TreeTagID_TBL.delete(@path) - Tk::BLT::Tree::Notify::NotifyID_TBL.delete(@path) - Tk::BLT::Tree::Trace::TraceID_TBL.delete(@path) + Tk::BLT::Tree::Node::TreeNodeID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Node::TreeNodeID_TBL.delete(@path) + } + Tk::BLT::Tree::Tag::TreeTagID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Tag::TreeTagID_TBL.delete(@path) + } + Tk::BLT::Tree::Notify::NotifyID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Notify::NotifyID_TBL.delete(@path) + } + Tk::BLT::Tree::Trace::TraceID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Trace::TraceID_TBL.delete(@path) + } end def tagid(tag) @@ -592,12 +719,14 @@ module Tk::BLT def delete(*nodes) tk_call('::blt::tree', 'delete', *(nodes.collect{|node| tagid(node)})) - nodes.each{|node| - if node.kind_of?(Tk::BLT::Tree::Node) - Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.id) - else - Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.to_s) - end + Tk::BLT::Tree::Node::TreeNodeID_TBL.mutex.synchronize{ + nodes.each{|node| + if node.kind_of?(Tk::BLT::Tree::Node) + Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.id) + else + Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.to_s) + end + } } self end @@ -728,7 +857,9 @@ module Tk::BLT id.delete else tk_call(@path, 'notify', 'delete', id) - Tk::BLT::Tree::Notify::NotifyID_TBL[@path].delete(id.to_s) + Tk::BLT::Tree::Notify::NotifyID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Notify::NotifyID_TBL[@path].delete(id.to_s) + } end self end @@ -835,7 +966,9 @@ module Tk::BLT def tag_forget(tag) tag = tag.id if tag.kind_of?(Tk::BLT::Tree::Tag) tk_call(@path, 'tag', 'forget', tag) - TreeTagID_TBL[@path].delete(tag) + TreeTagID_TBL.mutex.synchronize{ + TreeTagID_TBL[@path].delete(tag) + } self end @@ -889,7 +1022,9 @@ module Tk::BLT def trace_delete(*args) args = args.collect{|id| tagid(id)} tk_call(@path, 'trace', 'delete', *args) - args.each{|id| Tk::BLT::Tree::Trace::TraceID_TBL[@path].delete(id.to_s)} + Tk::BLT::Tree::Trace::TraceID_TBL.mutex.synchronize{ + args.each{|id| Tk::BLT::Tree::Trace::TraceID_TBL[@path].delete(id.to_s)} + } self end diff --git a/ext/tk/lib/tkextlib/blt/treeview.rb b/ext/tk/lib/tkextlib/blt/treeview.rb index 0343d28b9..fc890614b 100644 --- a/ext/tk/lib/tkextlib/blt/treeview.rb +++ b/ext/tk/lib/tkextlib/blt/treeview.rb @@ -239,6 +239,22 @@ class Tk::BLT::Treeview nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -273,8 +289,12 @@ class Tk::BLT::Treeview ######################## def __destroy_hook__ - Tk::BLT::Treeview::Node::TreeNodeID_TBL.delete(@path) - Tk::BLT::Treeview::Tag::TreeTagID_TBL.delete(@path) + Tk::BLT::Treeview::Node::TreeNodeID_TBL.mutex.synchronize{ + Tk::BLT::Treeview::Node::TreeNodeID_TBL.delete(@path) + } + Tk::BLT::Treeview::Tag::TreeTagID_TBL.mutex.synchronize{ + Tk::BLT::Treeview::Tag::TreeTagID_TBL.delete(@path) + } end def tagid(tag) @@ -472,6 +492,22 @@ class Tk::BLT::Treeview nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -967,22 +1003,47 @@ class Tk::BLT::Treeview::Node < TkObject include Tk::BLT::Treeview::TagOrID_Methods TreeNodeID_TBL = TkCore::INTERP.create_table - TreeNode_ID = ['blt_treeview_node'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TreeNodeID_TBL.clear } + (TreeNode_ID = ['blt_treeview_node'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + TreeNodeID_TBL.mutex.synchronize{ TreeNodeID_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless TreeNodeID_TBL[tpath] - if TreeNodeID_TBL[tpath][id] - TreeNodeID_TBL[tpath][id] - else - begin - self.new(tree, nil, nil, 'node'=>Integer(id)) - rescue + TreeNodeID_TBL.mutex.synchronize{ + if TreeNodeID_TBL[tpath] + if TreeNodeID_TBL[tpath][id] + TreeNodeID_TBL[tpath][id] + else + begin + # self.new(tree, nil, nil, 'node'=>Integer(id)) + unless (tk_call(@tpath, 'get', id)).empty? + id = Integer(id) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = id + TreeNodeID_TBL[@tpath] ||= {} + TreeNodeID_TBL[@tpath][@id] = self + } + obj + else + id + end + rescue + id + end + end + else id end - end + } end def self.new(tree, pos, parent=nil, keys={}) @@ -994,13 +1055,21 @@ class Tk::BLT::Treeview::Node < TkObject keys = _symbolkey2str(keys) tpath = tree.path - if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id]) - keys.delete('node') - tk_call(tree.path, 'move', id, pos, parent) if parent - return obj - end + TreeNodeID_TBL.mutex.synchronize{ + TreeNodeID_TBL[tpath] ||= {} + if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id]) + keys.delete('node') + tk_call(tree.path, 'move', id, pos, parent) if parent + return obj + end - super(tree, pos, parent, keys) + #super(tree, pos, parent, keys) + (obj = self.allocate).instance_eval{ + initialize(tree, pos, parent, keys) + TreeNodeID_TBL[tpath][@id] = self + } + obj + } end def initialize(tree, pos, parent, keys) @@ -1008,11 +1077,18 @@ class Tk::BLT::Treeview::Node < TkObject @tpath = @parent.path if (id = keys['node']) + # if tk_call(@tpath, 'get', id).empty? + # fail RuntimeError, "not exist the node '#{id}'" + # end @path = @id = id tk_call(@tpath, 'move', @id, pos, tagid(parent)) if parent + configure(keys) if keys && ! keys.empty? else - name = TreeNode_ID.join(TkCore::INTERP._ip_id_).freeze - TreeNode_ID[1].succ! + name = nil + TreeNode_ID.mutex.synchronize{ + name = TreeNode_ID.join(TkCore::INTERP._ip_id_).freeze + TreeNode_ID[1].succ! + } at = keys.delete['at'] @@ -1035,9 +1111,6 @@ class Tk::BLT::Treeview::Node < TkObject end @path = @id end - - TreeNodeID_TBL[@tpath] = {} unless TreeNodeID_TBL[@tpath] - TreeNodeID_TBL[@tpath][@id] = self end def id @@ -1051,37 +1124,66 @@ class Tk::BLT::Treeview::Tag < TkObject include Tk::BLT::Treeview::TagOrID_Methods TreeTagID_TBL = TkCore::INTERP.create_table - TreeTag_ID = ['blt_treeview_tag'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TreeTagID_TBL.clear } + (TreeTag_ID = ['blt_treeview_tag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } - def self.id2obj(tree, id) + TkCore::INTERP.init_ip_env{ + TreeTagID_TBL.mutex.synchronize{ TreeTagID_TBL.clear } + } + + def self.id2obj(tree, name) tpath = tree.path - return id unless TreeTagID_TBL[tpath] - if TreeTagID_TBL[tpath][id] - TreeTagID_TBL[tpath][id] - else - begin - self.new(tree, nil, nil, 'name'=>Integer(id)) - rescue + TreeTagID_TBL.mutex.synchronize{ + if TreeTagID_TBL[tpath] + if TreeTagID_TBL[tpath][name] + TreeTagID_TBL[tpath][name] + else + #self.new(tree, name) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = name + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } + obj + end + else id end - end + } end def self.new_by_name(tree, name, *ids) - if (obj = TreeTagID_TBL[tree.path][name]) - return obj - end - new([tree, name], ids) + TreeTagID_TBL.mutex.synchronize{ + unless (obj = TreeTagID_TBL[tree.path][name]) + (obj = self.allocate).instance_eval{ + initialize(tree, name, ids) + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } + end + obj + } end def self.new(tree, *ids) - if tree.kind_of?(Array) - super(tree[0], tree[1], ids) - else - super(tree, nil, ids) - end + TreeTagID_TBL.mutex.synchronize{ + (obj = self.allocate).instance_eval{ + if tree.kind_of?(Array) + initialize(tree[0], tree[1], ids) + else + initialize(tree, nil, ids) + end + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } + obj + } end def initialize(tree, name, ids) @@ -1091,13 +1193,12 @@ class Tk::BLT::Treeview::Tag < TkObject if name @path = @id = name else - @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_).freeze - TreeTag_ID[1].succ! + TreeTag_ID.mutex.synchronize{ + @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_).freeze + TreeTag_ID[1].succ! + } end - TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] - TreeTagID_TBL[@tpath][@id] = self - unless ids.empty? tk_call(@tpath, 'tag', 'add', @id, *(ids.collect{|id| tagid(id)})) end diff --git a/ext/tk/lib/tkextlib/blt/vector.rb b/ext/tk/lib/tkextlib/blt/vector.rb index 540b6b910..76c12a24e 100644 --- a/ext/tk/lib/tkextlib/blt/vector.rb +++ b/ext/tk/lib/tkextlib/blt/vector.rb @@ -23,14 +23,17 @@ module Tk::BLT end def self.names(pat=None) - simplelist(tk_call('::blt::vector', 'names', pat)).collect{|name| - if TkVar_ID_TBL[name] - TkVar_ID_TBL[name] - elsif name[0..1] == '::' && TkVar_ID_TBL[name[2..-1]] - TkVar_ID_TBL[name[2..-1]] - else - name - end + list = simplelist(tk_call('::blt::vector', 'names', pat)) + TkVar_ID_TBL.mutex.synchronize{ + list.collect{|name| + if TkVar_ID_TBL[name] + TkVar_ID_TBL[name] + elsif name[0..1] == '::' && TkVar_ID_TBL[name[2..-1]] + TkVar_ID_TBL[name[2..-1]] + else + name + end + } } end @@ -53,7 +56,9 @@ module Tk::BLT "#auto", *hash_kv(keys)) end - TkVar_ID_TBL[@id] = self + TkVar_ID_TBL.mutex.synchronize{ + TkVar_ID_TBL[@id] = self + } @def_default = false @default_val = nil @@ -221,13 +226,21 @@ module Tk::BLT class VectorAccess < Vector def self.new(name) - return TkVar_ID_TBL[name] if TkVar_ID_TBL[name] - super(name, size=nil, keys={}) + TkVar_ID_TBL.mutex.synchronize{ + if TkVar_ID_TBL[name] + TkVar_ID_TBL[name] + else + (obj = self.allocate).instance_eval{ + initialize(name) + TkVar_ID_TBL[@id] = self + } + obj + end + } end def initialize(vec_name) @id = vec_name - TkVar_ID_TBL[@id] = self @def_default = false @default_val = nil diff --git a/ext/tk/lib/tkextlib/blt/watch.rb b/ext/tk/lib/tkextlib/blt/watch.rb index ae5e50f12..2daf417e0 100644 --- a/ext/tk/lib/tkextlib/blt/watch.rb +++ b/ext/tk/lib/tkextlib/blt/watch.rb @@ -13,11 +13,23 @@ module Tk::BLT TkCommandNames = ['::blt::watch'.freeze].freeze WATCH_ID_TBL = TkCore::INTERP.create_table - BLT_WATCH_ID = ['blt_watch_id'.freeze, '00000'.taint].freeze + + (BLT_WATCH_ID = ['blt_watch_id'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + WATCH_ID_TBL.mutex.synchronize{ WATCH_ID_TBL.clear } + } def self.names(state = None) - tk_split_list(tk_call('::blt::watch', 'names', state)).collect{|name| - WATCH_ID_TBL[name] || name + lst = tk_split_list(tk_call('::blt::watch', 'names', state)) + WATCH_ID_TBL.mutex.synchronize{ + lst.collect{|name| + WATCH_ID_TBL[name] || name + } } end @@ -45,13 +57,17 @@ module Tk::BLT if name @id = name.to_s else - @id = BLT_WATCH_ID.join(TkCore::INTERP._ip_id_) - BLT_WATCH_ID[1].succ! + BLT_WATCH_ID.mutex.synchronize{ + @id = BLT_WATCH_ID.join(TkCore::INTERP._ip_id_) + BLT_WATCH_ID[1].succ! + } end @path = @id - WATCH_ID_TBL[@id] = self + WATCH_ID_TBL.mutex.synchronize{ + WATCH_ID_TBL[@id] = self + } tk_call('::blt::watch', 'create', @id, *hash_kv(keys)) end diff --git a/ext/tk/lib/tkextlib/bwidget/buttonbox.rb b/ext/tk/lib/tkextlib/bwidget/buttonbox.rb index a8f23e874..8d6d21218 100644 --- a/ext/tk/lib/tkextlib/bwidget/buttonbox.rb +++ b/ext/tk/lib/tkextlib/bwidget/buttonbox.rb @@ -40,7 +40,13 @@ class Tk::BWidget::ButtonBox def add(keys={}, &b) win = window(tk_send('add', *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end @@ -62,7 +68,13 @@ class Tk::BWidget::ButtonBox def insert(idx, keys={}, &b) win = window(tk_send('insert', tagid(idx), *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/combobox.rb b/ext/tk/lib/tkextlib/bwidget/combobox.rb index 31f71c3aa..1c58a4ccb 100644 --- a/ext/tk/lib/tkextlib/bwidget/combobox.rb +++ b/ext/tk/lib/tkextlib/bwidget/combobox.rb @@ -25,7 +25,13 @@ class Tk::BWidget::ComboBox def get_listbox(&b) win = window(tk_send_without_enc('getlistbox')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/dialog.rb b/ext/tk/lib/tkextlib/bwidget/dialog.rb index ae5f0238a..0ddee21d0 100644 --- a/ext/tk/lib/tkextlib/bwidget/dialog.rb +++ b/ext/tk/lib/tkextlib/bwidget/dialog.rb @@ -112,19 +112,37 @@ class Tk::BWidget::Dialog def add(keys={}, &b) win = window(tk_send('add', *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_frame(&b) win = window(tk_send('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_buttonbox(&b) win = window(@path + '.bbox') - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/labelframe.rb b/ext/tk/lib/tkextlib/bwidget/labelframe.rb index f7b267eeb..dc221806e 100644 --- a/ext/tk/lib/tkextlib/bwidget/labelframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/labelframe.rb @@ -40,7 +40,13 @@ class Tk::BWidget::LabelFrame end def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end end diff --git a/ext/tk/lib/tkextlib/bwidget/listbox.rb b/ext/tk/lib/tkextlib/bwidget/listbox.rb index 126750066..d8cd72fec 100644 --- a/ext/tk/lib/tkextlib/bwidget/listbox.rb +++ b/ext/tk/lib/tkextlib/bwidget/listbox.rb @@ -211,14 +211,26 @@ class Tk::BWidget::ListBox::Item include TkTreatTagFont ListItem_TBL = TkCore::INTERP.create_table - ListItem_ID = ['bw:item'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ ListItem_TBL.clear } + (ListItem_ID = ['bw:item'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + ListItem_TBL.mutex.synchronize{ ListItem_TBL.clear } + } def self.id2obj(lbox, id) lpath = lbox.path - return id unless ListItem_TBL[lpath] - ListItem_TBL[lpath][id]? ListItem_TBL[lpath][id]: id + ListItem_TBL.mutex.synchronize{ + if ListItem_TBL[lpath] + ListItem_TBL[lpath][id]? ListItem_TBL[lpath][id]: id + else + id + end + } end def initialize(lbox, *args) @@ -250,13 +262,17 @@ class Tk::BWidget::ListBox::Item if keys.key?('itemname') @path = @id = keys.delete('itemname') else - @path = @id = ListItem_ID.join(TkCore::INTERP._ip_id_) - ListItem_ID[1].succ! + ListItem_ID.mutex.synchronize{ + @path = @id = ListItem_ID.join(TkCore::INTERP._ip_id_) + ListItem_ID[1].succ! + } end - ListItem_TBL[@id] = self - ListItem_TBL[@lpath] = {} unless ListItem_TBL[@lpath] - ListItem_TBL[@lpath][@id] = self + ListItem_TBL.mutex.synchronize{ + ListItem_TBL[@id] = self + ListItem_TBL[@lpath] = {} unless ListItem_TBL[@lpath] + ListItem_TBL[@lpath][@id] = self + } @listbox.insert(index, @id, keys) end diff --git a/ext/tk/lib/tkextlib/bwidget/mainframe.rb b/ext/tk/lib/tkextlib/bwidget/mainframe.rb index c54e87855..de66eaf81 100644 --- a/ext/tk/lib/tkextlib/bwidget/mainframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/mainframe.rb @@ -41,37 +41,73 @@ class Tk::BWidget::MainFrame def add_indicator(keys={}, &b) win = window(tk_send('addindicator', *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def add_toolbar(&b) win = window(tk_send('addtoolbar')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_frame(&b) win = window(tk_send('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_indicator(idx, &b) win = window(tk_send('getindicator', idx)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_menu(menu_id, &b) win = window(tk_send('getmenu', menu_id)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_toolbar(idx, &b) win = window(tk_send('gettoolbar', idx)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/messagedlg.rb b/ext/tk/lib/tkextlib/bwidget/messagedlg.rb index 9c946d063..cc8a996f4 100644 --- a/ext/tk/lib/tkextlib/bwidget/messagedlg.rb +++ b/ext/tk/lib/tkextlib/bwidget/messagedlg.rb @@ -173,6 +173,9 @@ class Tk::BWidget::MessageDlg end def create - num_or_str(tk_call(self.class::TkCommandNames[0], @path, *hash_kv(@keys))) + # return the index of the pressed button, or nil if it is destroyed + ret = num_or_str(tk_call(self.class::TkCommandNames[0], + @path, *hash_kv(@keys))) + (ret < 0)? nil: ret end end diff --git a/ext/tk/lib/tkextlib/bwidget/notebook.rb b/ext/tk/lib/tkextlib/bwidget/notebook.rb index 5146d4915..423943619 100644 --- a/ext/tk/lib/tkextlib/bwidget/notebook.rb +++ b/ext/tk/lib/tkextlib/bwidget/notebook.rb @@ -89,7 +89,13 @@ class Tk::BWidget::NoteBook def add(page, &b) win = window(tk_send('add', tagid(page))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end @@ -105,7 +111,13 @@ class Tk::BWidget::NoteBook def get_frame(page, &b) win = window(tk_send('getframe', tagid(page))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end @@ -115,7 +127,13 @@ class Tk::BWidget::NoteBook def insert(index, page, keys={}, &b) win = window(tk_send('insert', index, tagid(page), *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb b/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb index fc01284be..fbc2c1125 100644 --- a/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb +++ b/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb @@ -26,7 +26,13 @@ class Tk::BWidget::PagesManager def add(page, &b) win = window(tk_send('add', tagid(page))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end @@ -42,7 +48,13 @@ class Tk::BWidget::PagesManager def get_frame(page, &b) win = window(tk_send('getframe', tagid(page))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/panedwindow.rb b/ext/tk/lib/tkextlib/bwidget/panedwindow.rb index 19982c609..4d979fd52 100644 --- a/ext/tk/lib/tkextlib/bwidget/panedwindow.rb +++ b/ext/tk/lib/tkextlib/bwidget/panedwindow.rb @@ -25,7 +25,13 @@ class Tk::BWidget::PanedWindow def get_frame(idx, &b) win = window(tk_send_without_enc('getframe', idx)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end end diff --git a/ext/tk/lib/tkextlib/bwidget/panelframe.rb b/ext/tk/lib/tkextlib/bwidget/panelframe.rb index 13f8817d7..84bae0768 100644 --- a/ext/tk/lib/tkextlib/bwidget/panelframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/panelframe.rb @@ -36,7 +36,13 @@ class Tk::BWidget::PanelFrame def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/progressdlg.rb b/ext/tk/lib/tkextlib/bwidget/progressdlg.rb index fbf00f3b0..32600255d 100644 --- a/ext/tk/lib/tkextlib/bwidget/progressdlg.rb +++ b/ext/tk/lib/tkextlib/bwidget/progressdlg.rb @@ -51,4 +51,8 @@ class Tk::BWidget::ProgressDlg def value= (val) @keys['variable'].value = val end + + def create + window(tk_call(self.class::TkCommandNames[0], @path, *hash_kv(@keys))) + end end diff --git a/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb b/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb index a3986681a..010c960ec 100644 --- a/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb @@ -23,7 +23,13 @@ class Tk::BWidget::ScrollableFrame def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb b/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb index e9e53235b..3599fd845 100644 --- a/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb +++ b/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb @@ -21,7 +21,13 @@ class Tk::BWidget::ScrolledWindow def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/selectcolor.rb b/ext/tk/lib/tkextlib/bwidget/selectcolor.rb index 742a84cd8..0f9014f8d 100644 --- a/ext/tk/lib/tkextlib/bwidget/selectcolor.rb +++ b/ext/tk/lib/tkextlib/bwidget/selectcolor.rb @@ -10,6 +10,11 @@ require 'tkextlib/bwidget/messagedlg' module Tk module BWidget class SelectColor < Tk::BWidget::MessageDlg + class Dialog < Tk::BWidget::SelectColor + end + class Menubutton < Tk::Menubutton + end + MenuButton = Menubutton end end end @@ -43,3 +48,26 @@ class Tk::BWidget::SelectColor tk_call('SelectColor::setcolor', idx, color) end end + +class Tk::BWidget::SelectColor::Dialog + def create_self(keys) + super(keys) + @keys['type'] = 'dialog' + end + + def create + @keys['type'] = 'dialog' # 'dialog' type returns color + tk_call(Tk::BWidget::SelectColor::TkCommandNames[0], + @path, *hash_kv(@keys)) + end +end + +class Tk::BWidget::SelectColor::Menubutton + def create_self(keys) + keys = {} unless keys + keys = _symbolkey2str(keys) + keys['type'] = 'menubutton' # 'toolbar' type returns widget path + window(tk_call(Tk::BWidget::SelectColor::TkCommandNames[0], + @path, *hash_kv(keys))) + end +end diff --git a/ext/tk/lib/tkextlib/bwidget/selectfont.rb b/ext/tk/lib/tkextlib/bwidget/selectfont.rb index 478787602..e53eb3b5b 100644 --- a/ext/tk/lib/tkextlib/bwidget/selectfont.rb +++ b/ext/tk/lib/tkextlib/bwidget/selectfont.rb @@ -66,7 +66,7 @@ class Tk::BWidget::SelectFont::Dialog end def create - @keys['type'] = 'dialog' + @keys['type'] = 'dialog' # 'dialog' type returns font name tk_call(Tk::BWidget::SelectFont::TkCommandNames[0], @path, *hash_kv(@keys)) end end @@ -79,7 +79,8 @@ class Tk::BWidget::SelectFont::Toolbar def create_self(keys) keys = {} unless keys keys = _symbolkey2str(keys) - keys['type'] = 'toolbar' - tk_call(Tk::BWidget::SelectFont::TkCommandNames[0], @path, *hash_kv(keys)) + keys['type'] = 'toolbar' # 'toolbar' type returns widget path + window(tk_call(Tk::BWidget::SelectFont::TkCommandNames[0], + @path, *hash_kv(keys))) end end diff --git a/ext/tk/lib/tkextlib/bwidget/statusbar.rb b/ext/tk/lib/tkextlib/bwidget/statusbar.rb index df16e4c0b..39c678d37 100644 --- a/ext/tk/lib/tkextlib/bwidget/statusbar.rb +++ b/ext/tk/lib/tkextlib/bwidget/statusbar.rb @@ -36,7 +36,13 @@ class Tk::BWidget::StatusBar def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/titleframe.rb b/ext/tk/lib/tkextlib/bwidget/titleframe.rb index f51949043..68534e66e 100644 --- a/ext/tk/lib/tkextlib/bwidget/titleframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/titleframe.rb @@ -21,7 +21,13 @@ class Tk::BWidget::TitleFrame def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end end diff --git a/ext/tk/lib/tkextlib/bwidget/tree.rb b/ext/tk/lib/tkextlib/bwidget/tree.rb index e7178debe..7a46db575 100644 --- a/ext/tk/lib/tkextlib/bwidget/tree.rb +++ b/ext/tk/lib/tkextlib/bwidget/tree.rb @@ -263,14 +263,26 @@ class Tk::BWidget::Tree::Node include TkTreatTagFont TreeNode_TBL = TkCore::INTERP.create_table - TreeNode_ID = ['bw:node'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TreeNode_TBL.clear } + (TreeNode_ID = ['bw:node'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + TreeNode_TBL.mutex.synchronize{ TreeNode_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless TreeNode_TBL[tpath] - TreeNode_TBL[tpath][id]? TreeNode_TBL[tpath][id]: id + TreeNode_TBL.mutex.synchronize{ + if TreeNode_TBL[tpath] + TreeNode_TBL[tpath][id]? TreeNode_TBL[tpath][id]: id + else + id + end + } end def initialize(tree, *args) @@ -311,13 +323,17 @@ class Tk::BWidget::Tree::Node if keys.key?('nodename') @path = @id = keys.delete('nodename') else - @path = @id = TreeNode_ID.join(TkCore::INTERP._ip_id_) - TreeNode_ID[1].succ! + TreeNode_ID.mutex.synchronize{ + @path = @id = TreeNode_ID.join(TkCore::INTERP._ip_id_) + TreeNode_ID[1].succ! + } end - TreeNode_TBL[@id] = self - TreeNode_TBL[@tpath] = {} unless TreeNode_TBL[@tpath] - TreeNode_TBL[@tpath][@id] = self + TreeNode_TBL.mutex.synchronize{ + TreeNode_TBL[@id] = self + TreeNode_TBL[@tpath] = {} unless TreeNode_TBL[@tpath] + TreeNode_TBL[@tpath][@id] = self + } @tree.insert(index, parent, @id, keys) end diff --git a/ext/tk/lib/tkextlib/bwidget/widget.rb b/ext/tk/lib/tkextlib/bwidget/widget.rb index 568e503a8..34e51308a 100644 --- a/ext/tk/lib/tkextlib/bwidget/widget.rb +++ b/ext/tk/lib/tkextlib/bwidget/widget.rb @@ -43,7 +43,13 @@ module Tk::BWidget::Widget def self.create(klass, path, rename=None, &b) win = window(tk_call('Widget::create', klass, path, rename)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/itcl/incr_tcl.rb b/ext/tk/lib/tkextlib/itcl/incr_tcl.rb index 07abf3a7b..2b75d62eb 100644 --- a/ext/tk/lib/tkextlib/itcl/incr_tcl.rb +++ b/ext/tk/lib/tkextlib/itcl/incr_tcl.rb @@ -40,16 +40,22 @@ module Tk class ItclObject < TkObject ITCL_CLASSNAME = ''.freeze - ITCL_OBJ_ID = ['itclobj'.freeze, '00000'.taint].freeze + (ITCL_OBJ_ID = ['itclobj'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } ITCL_OBJ_TBL = {}.taint def initialize(*args) if (@klass = self.class::ITCL_CLASSNAME).empty? fail RuntimeError, 'unknown itcl class (abstract class?)' end - @id = Tk::Itcl::ItclObject::TCL_OBJ_ID.join(TkCore::INTERP._ip_id_) + Tk::Itcl::ItclObject::ITCL_OBJ_ID.mutex.synchronize{ + @id = Tk::Itcl::ItclObject::TCL_OBJ_ID.join(TkCore::INTERP._ip_id_) + Tk::Itcl::ItclObject::ITCL_OBJ_ID[1].succ! + } @path = @id - Tk::Itcl::ItclObject::ITCL_OBJ_ID[1].succ! end def self.call_proc(name, *args) diff --git a/ext/tk/lib/tkextlib/itk/incr_tk.rb b/ext/tk/lib/tkextlib/itk/incr_tk.rb index c7b4e40af..e06deb552 100644 --- a/ext/tk/lib/tkextlib/itk/incr_tk.rb +++ b/ext/tk/lib/tkextlib/itk/incr_tk.rb @@ -145,9 +145,16 @@ module Tk private :__config_cmd ComponentID_TBL = TkCore::INTERP.create_table - Itk_Component_ID = ['itk:component'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ ComponentID_TBL.clear } + (Itk_Component_ID = ['itk:component'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + ComponentID_TBL.mutex.synchronize{ ComponentID_TBL.clear } + } def self.id2obj(master, id) if master.kind_of?(TkObject) @@ -155,8 +162,13 @@ module Tk else master = master.to_s end - return id unless ComponentID_TBL.key?(master) - (ComponentID_TBL[master].key?(id))? ComponentID_TBL[master][id]: id + ComponentID_TBL.mutex.synchronize{ + if ComponentID_TBL.key?(master) + (ComponentID_TBL[master].key?(id))? ComponentID_TBL[master][id]: id + else + id + end + } end def self.new(master, component=nil) @@ -171,17 +183,21 @@ module Tk elsif component component = component.to_s else - component = Itk_Component_ID.join(TkCore::INTERP._ip_id_) - Itk_Component_ID[1].succ! + Itk_Component_ID.mutex.synchronize{ + component = Itk_Component_ID.join(TkCore::INTERP._ip_id_) + Itk_Component_ID[1].succ! + } end - if ComponentID_TBL.key?(master) - if ComponentID_TBL[master].key?(component) - return ComponentID_TBL[master][component] + ComponentID_TBL.mutex.synchronize{ + if ComponentID_TBL.key?(master) + if ComponentID_TBL[master].key?(component) + return ComponentID_TBL[master][component] + end + else + ComponentID_TBL[master] = {} end - else - ComponentID_TBL[master] = {} - end + } super(master, component) end @@ -190,7 +206,9 @@ module Tk @master = master @component = component - ComponentID_TBL[@master][@component] = self + ComponentID_TBL.mutex.synchronize{ + ComponentID_TBL[@master][@component] = self + } begin @widget = window(tk_call(@master, 'component', @component)) diff --git a/ext/tk/lib/tkextlib/iwidgets/calendar.rb b/ext/tk/lib/tkextlib/iwidgets/calendar.rb index 0152f8593..236ca96f0 100644 --- a/ext/tk/lib/tkextlib/iwidgets/calendar.rb +++ b/ext/tk/lib/tkextlib/iwidgets/calendar.rb @@ -45,6 +45,23 @@ class Tk::Iwidgets::Calendar class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [?d, ?s, :date], nil ] PROC_TBL = [ [?s, TkComm.method(:string) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) diff --git a/ext/tk/lib/tkextlib/iwidgets/entryfield.rb b/ext/tk/lib/tkextlib/iwidgets/entryfield.rb index 6aa933ce0..1f9effb46 100644 --- a/ext/tk/lib/tkextlib/iwidgets/entryfield.rb +++ b/ext/tk/lib/tkextlib/iwidgets/entryfield.rb @@ -42,6 +42,23 @@ class Tk::Iwidgets::Entryfield [ ?w, TkComm.method(:window) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); end diff --git a/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb b/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb index 028f6ac0e..4e7d8f857 100644 --- a/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb +++ b/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb @@ -30,6 +30,23 @@ class Tk::Iwidgets::Hierarchy class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [?n, ?s, :node], nil ] PROC_TBL = [ [?s, TkComm.method(:string) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -57,6 +74,22 @@ class Tk::Iwidgets::Hierarchy nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -78,6 +111,23 @@ class Tk::Iwidgets::Hierarchy nil ] PROC_TBL = [ [ ?s, TkComm.method(:string) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) diff --git a/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb b/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb index 407c8f2aa..b07602e34 100644 --- a/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb +++ b/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb @@ -171,10 +171,16 @@ class Tk::Iwidgets::Scrolledcanvas end def delete(*args) - if TkcItem::CItemID_TBL[self.path] + tbl = nil + TkcItem::CItemID_TBL.mutex.synchronize{ + tbl = TkcItem::CItemID_TBL[self.path] + } + if tbl find('withtag', *args).each{|item| if item.kind_of?(TkcItem) - TkcItem::CItemID_TBL[self.path].delete(item.id) + TkcItem::CItemID_TBL.mutex.synchronize{ + tbl.delete(item.id) + } end } end diff --git a/ext/tk/lib/tkextlib/iwidgets/spinner.rb b/ext/tk/lib/tkextlib/iwidgets/spinner.rb index 174b9bd50..126cfe7c9 100644 --- a/ext/tk/lib/tkextlib/iwidgets/spinner.rb +++ b/ext/tk/lib/tkextlib/iwidgets/spinner.rb @@ -37,6 +37,23 @@ class Tk::Iwidgets::Spinner [ ?w, TkComm.method(:window) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); end diff --git a/ext/tk/lib/tkextlib/tcllib/ico.rb b/ext/tk/lib/tkextlib/tcllib/ico.rb index 3beeb11a4..8c92926a4 100644 --- a/ext/tk/lib/tkextlib/tcllib/ico.rb +++ b/ext/tk/lib/tkextlib/tcllib/ico.rb @@ -94,8 +94,10 @@ class Tk::Tcllib::ICO if keys.key?('name') @path = keys['name'].to_s else - @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_) - Tk_Image_ID[1].succ! + Tk_Image_ID.mutex.synchronize{ + @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_) + Tk_Image_ID[1].succ! + } end tk_call_without_enc('::ico::getIcon', file, index, '-name', @path, '-format', 'image', *hash_kv(keys, true)) diff --git a/ext/tk/lib/tkextlib/tcllib/plotchart.rb b/ext/tk/lib/tkextlib/tcllib/plotchart.rb index cde42c8a0..06ab20f3e 100644 --- a/ext/tk/lib/tkextlib/tcllib/plotchart.rb +++ b/ext/tk/lib/tkextlib/tcllib/plotchart.rb @@ -265,7 +265,9 @@ module Tk::Tcllib::Plotchart private :_create_chart def __destroy_hook__ - Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{ + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + } end def plot(series, x, y) @@ -374,7 +376,9 @@ module Tk::Tcllib::Plotchart private :_create_chart def __destroy_hook__ - Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{ + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + } end def plot(series, radius, angle) @@ -645,7 +649,9 @@ module Tk::Tcllib::Plotchart private :_create_chart def __destroy_hook__ - Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{ + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + } end def plot(series, dat, col=None) @@ -834,23 +840,38 @@ module Tk::Tcllib::Plotchart ############################ class PlotSeries < TkObject SeriesID_TBL = TkCore::INTERP.create_table - Series_ID = ['series'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ SeriesID_TBL.clear } + + (Series_ID = ['series'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + TkCore::INTERP.init_ip_env{ + SeriesID_TBL.mutex.synchronize{ SeriesID_TBL.clear } + } def self.id2obj(chart, id) path = chart.path - return id unless SeriesID_TBL[path] - SeriesID_TBL[path][id]? SeriesID_TBL[path][id]: id + SeriesID_TBL.mutex.synchronize{ + if SeriesID_TBL[path] + SeriesID_TBL[path][id]? SeriesID_TBL[path][id]: id + else + id + end + } end def initialize(chart, keys=nil) @parent = @chart_obj = chart @ppath = @chart_obj.path - @path = @series = @id = Series_ID.join(TkCore::INTERP._ip_id_) - # SeriesID_TBL[@id] = self - SeriesID_TBL[@ppath] = {} unless SeriesID_TBL[@ppath] - SeriesID_TBL[@ppath][@id] = self - Series_ID[1].succ! + Series_ID.mutex.synchronize{ + @path = @series = @id = Series_ID.join(TkCore::INTERP._ip_id_) + Series_ID[1].succ! + } + SeriesID_TBL.mutex.synchronize{ + SeriesID_TBL[@ppath] ||= {} + SeriesID_TBL[@ppath][@id] = self + } dataconfig(keys) if keys.kind_of?(Hash) end diff --git a/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb b/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb index 92dde65ce..b366e0198 100644 --- a/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb +++ b/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb @@ -125,7 +125,9 @@ module Tk::Tcllib::Tkpiechart def delete tk_call_without_enc('::stooop::delete', @tag_key) - CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + CItemID_TBL.mutex.synchronize{ + CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + } self end @@ -184,8 +186,10 @@ module Tk::Tcllib::Tkpiechart @id = "slices(#{@tag_key})" @tag = TkcNamedTag.new(@pie.canvas, @id) - CItemID_TBL[@path] = {} unless CItemID_TBL[@path] - CItemID_TBL[@path][@id] = self + CItemID_TBL.mutex.synchronize{ + CItemID_TBL[@path] = {} unless CItemID_TBL[@path] + CItemID_TBL[@path][@id] = self + } end def tag_key @@ -200,7 +204,9 @@ module Tk::Tcllib::Tkpiechart def delete tk_call_without_enc('pie::deleteSlice', @pie.tag_key, @tag_key) - CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + CItemID_TBL.mutex.synchronize{ + CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + } @pie._delete_slice(self) self end diff --git a/ext/tk/lib/tkextlib/tile.rb b/ext/tk/lib/tkextlib/tile.rb index b527935a6..02473d57a 100644 --- a/ext/tk/lib/tkextlib/tile.rb +++ b/ext/tk/lib/tkextlib/tile.rb @@ -18,11 +18,8 @@ require 'tkextlib/tile/setup.rb' # TkPackage.require('tile', '0.7') if Tk::TK_MAJOR_VERSION > 8 || (Tk::TK_MAJOR_VERSION == 8 && Tk::TK_MINOR_VERSION >= 5) - begin - verstr = TkPackage.require('Ttk') - rescue RuntimeError - verstr = TkPackage.require('tile') - end + TkPackage.require('tile') # for compatibility (version check of 'tile') + verstr = TkPackage.require('Ttk') else verstr = TkPackage.require('tile') end @@ -101,16 +98,97 @@ module Tk end def self.__Import_Tile_Widgets__! + warn 'Warning: "Tk::Tile::__Import_Tile_Widgets__!" is obsolete.' << + ' To control default widget set, use "Tk.default_widget_set = :Ttk"' Tk.tk_call('namespace', 'import', '-force', 'ttk::*') end - def self.load_images(imgdir, pat=TkComm::None) - images = Hash[*TkComm.simplelist(Tk.tk_call('::tile::LoadImages', - imgdir, pat))] - images.keys.each{|k| - images[k] = TkPhotoImage.new(:imagename=>images[k], - :without_creating=>true) + def self.__define_LoadImages_proc_for_compatibility__! + # Ttk 8.5 (Tile 0.8) lost 'LoadImages' utility procedure. + # So, some old scripts doen't work, because those scripts use the + # procedure to define local styles. + # Of course, rewriting such Tcl/Tk scripts isn't difficult for + # Tcl/Tk users. However, it may be troublesome for Ruby/Tk users + # who use such Tcl/Tk scripts as it is. + # This method may help Ruby/Tk users who don't want to modify old + # Tcl/Tk scripts for the latest version of Ttk (Tile) extension. + # This method defines a comaptible 'LoadImages' procedure on the + # Tcl/Tk interpreter working under Ruby/Tk. + # Please give attention to use this method. It may conflict with + # some definitions on Tcl/Tk scripts. + klass_name = self.name + proc_name = 'LoadImages' + if Tk::Tile::USE_TTK_NAMESPACE + ns_list = ['::tile'] + if Tk.info(:commands, "::ttk::#{proc_name}").empty? + ns_list << '::ttk' + end + else # Tk::Tile::USE_TILE_NAMESPACE + ns_list = ['::ttk'] + if Tk.info(:commands, "::tile::#{proc_name}").empty? + ns_list << '::tile' + end + end + + ns_list.each{|ns| + cmd = "#{ns}::#{proc_name}" + unless Tk.info(:commands, cmd).empty? + fail RuntimeError, "can't define '#{cmd}' command (already exist)" + end + TkNamespace.eval(ns){ + TkCore::INTERP.add_tk_procs(proc_name, 'imgdir {patterns {*.gif}}', + <<-'EOS') + foreach pattern $patterns { + foreach file [glob -directory $imgdir $pattern] { + set img [file tail [file rootname $file]] + if {![info exists images($img)]} { + set images($img) [image create photo -file $file] + } + } + } + return [array get images] + EOS + } } + end + + def self.load_images(imgdir, pat=nil) + if Tk::Tile::TILE_SPEC_VERSION_ID < 8 + if Tk::Tile::USE_TTK_NAMESPACE + cmd = '::ttk::LoadImages' + else # Tk::Tile::USE_TILE_NAMESPACE + cmd = '::tile::LoadImages' + end + pat ||= TkComm::None + images = Hash[*TkComm.simplelist(Tk.tk_call(cmd, imgdir, pat))] + images.keys.each{|k| + images[k] = TkPhotoImage.new(:imagename=>images[k], + :without_creating=>true) + } + else ## TILE_SPEC_VERSION_ID >= 8 + pat ||= '*.gif' + if pat.kind_of?(Array) + pat_list = pat + else + pat_list = [ pat ] + end + Dir.chdir(imgdir){ + pat_list.each{|pat| + Dir.glob(pat).each{|f| + img = File.basename(f, '.*') + unless TkComm.bool(Tk.info('exists', "images(#{img})")) + Tk.tk_call('set', "images(#{img})", + Tk.tk_call('image', 'create', 'photo', '-file', f)) + end + } + } + } + images = Hash[*TkComm.simplelist(Tk.tk_call('array', 'get', 'images'))] + images.keys.each{|k| + images[k] = TkPhotoImage.new(:imagename=>images[k], + :without_creating=>true) + } + end images end @@ -120,11 +198,20 @@ module Tk end module KeyNav - def self.enableMnemonics(w) - Tk.tk_call('::keynav::enableMnemonics', w) - end - def self.defaultButton(w) - Tk.tk_call('::keynav::defaultButton', w) + if Tk::Tile::TILE_SPEC_VERSION_ID < 8 + def self.enableMnemonics(w) + Tk.tk_call('::keynav::enableMnemonics', w) + end + def self.defaultButton(w) + Tk.tk_call('::keynav::defaultButton', w) + end + else # dummy + def self.enableMnemonics(w) + "" + end + def self.defaultButton(w) + "" + end end end @@ -139,6 +226,12 @@ module Tk Menu = 'TkMenuFont' SmallCaption = 'TkSmallCaptionFont' Icon = 'TkIconFont' + + TkFont::SYSTEM_FONT_NAMES.add [ + 'TkDefaultFont', 'TkTextFont', 'TkHeadingFont', + 'TkCaptionFont', 'TkTooltipFont', 'TkFixedFont', + 'TkMenuFont', 'TkSmallCaptionFont', 'TkIconFont' + ] end module ParseStyleLayout @@ -177,7 +270,7 @@ module Tk end private :__val2ruby_optkeys - def instate(state, script=nil, &b) + def ttk_instate(state, script=nil, &b) if script tk_send('instate', state, script) elsif b @@ -186,19 +279,30 @@ module Tk bool(tk_send('instate', state)) end end + alias tile_instate ttk_instate - def state(state=nil) + def ttk_state(state=nil) if state tk_send('state', state) else list(tk_send('state')) end end + alias tile_state ttk_state - def identify(x, y) + def ttk_identify(x, y) ret = tk_send_without_enc('identify', x, y) (ret.empty?)? nil: ret end + alias tile_identify ttk_identify + + # remove instate/state/identify method + # to avoid the conflict with widget options + if Tk.const_defined?(:USE_OBSOLETE_TILE_STATE_METHOD) && Tk::USE_OBSOLETE_TILE_STATE_METHOD + alias instate ttk_instate + alias state ttk_state + alias identify ttk_identify + end end ###################################### diff --git a/ext/tk/lib/tkextlib/tile/style.rb b/ext/tk/lib/tkextlib/tile/style.rb index e01011cb2..bf8acb34b 100644 --- a/ext/tk/lib/tkextlib/tile/style.rb +++ b/ext/tk/lib/tkextlib/tile/style.rb @@ -19,8 +19,93 @@ end class << Tk::Tile::Style if Tk::Tile::TILE_SPEC_VERSION_ID < 8 TkCommandNames = ['style'.freeze].freeze - else + + # --- Tk::Tile::Style.__define_wrapper_proc_for_compatibility__! --- + # On Ttk (Tile) extension, 'style' command has imcompatible changes + # depend on the version of the extention. It requires modifying the + # Tcl/Tk scripts to define local styles. The rule for modification + # is a simple one. But, if users want to keep compatibility between + # versions of the extension, they will have to contrive to do that. + # It may be troublesome, especially for Ruby/Tk users. + # This method may help such work. This method make some definitions + # on the Tcl/Tk interpreter to work with different version of style + # command format. Please give attention to use this method. It may + # conflict with some definitions on Tcl/Tk scripts. + if Tk::Tile::TILE_SPEC_VERSION_ID < 7 + def __define_wrapper_proc_for_compatibility__! + unless Tk.info(:commands, '::ttk::style').empty? + fail RuntimeError, + "can't define ':ttk::style' command (already exist)" + end + TkCore::INTERP.add_tk_procs('::ttk::style', 'args', <<-'EOS') + if [string equal [lrange $args 0 1] {element create}] { + if [string equal [lindex $args 3] image] { + set spec [lindex $args 4] + set map [lrange $spec 1 end] + if [llength $map] { + # return [eval [concat [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]] + return [uplevel 1 [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]] + } + } + } + # return [eval "::style $args"] + return [uplevel 1 ::style $args] + EOS + ######################### + end + else ### TILE_SPEC_VERSION_ID == 7 + def __define_wrapper_proc_for_compatibility__! + unless Tk.info(:commands, '::ttk::style').empty? + fail RuntimeError, + "can't define ':ttk::style' command (already exist)" + end + TkCore::INTERP.add_tk_procs('::ttk::style', 'args', <<-'EOS') + if [string equal [lrange $args 0 1] {element create}] { + if [string equal [lindex $args 3] image] { + set spec [lindex $args 4] + set map [lrange $spec 1 end] + if [llength $map] { + # return [eval [concat [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]] + return [uplevel 1 [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]] + } + } + } elseif [string equal [lindex $args 0] default] { + # return [eval "::style [lreplace $args 0 0 configure]"] + return [uplevel 1 ::style [lreplace $args 0 0 configure]] + } + # return [eval "::style $args"] + return [uplevel 1 ::style $args] + EOS + ######################### + end + end + else ### TILE_SPEC_VERSION_ID >= 8 TkCommandNames = ['::ttk::style'.freeze].freeze + + def __define_wrapper_proc_for_compatibility__! + unless Tk.info(:commands, '::style').empty? + fail RuntimeError, "can't define '::style' command (already exist)" + end + TkCore::INTERP.add_tk_procs('::style', 'args', <<-'EOS') + if [string equal [lrange $args 0 1] {element create}] { + if [string equal [lindex $args 3] image] { + set name [lindex $args 4] + set opts [lrange $args 5 end] + set idx [lsearch $opts -map] + if {$idx >= 0 && [expr $idx % 2 == 0]} { + # return [eval [concat [list ::ttk::style element create [lindex $args 2] image [concat $name [lindex $opts [expr $idx + 1]]]] [lreplace $opts $idx [expr $idx + 1]]]] + return [uplevel 1 [list ::ttk::style element create [lindex $args 2] image [concat $name [lindex $opts [expr $idx + 1]]]] [lreplace $opts $idx [expr $idx + 1]]] + } + } + } elseif [string equal [lindex $args 0] default] { + # return [eval "::ttk::style [lreplace $args 0 0 configure]"] + return [uplevel 1 ::ttk::style [lreplace $args 0 0 configure]] + } + # return [eval "::ttk::style $args"] + return [uplevel 1 ::ttk::style $args] + EOS + ######################### + end end def configure(style=nil, keys=nil) @@ -98,7 +183,52 @@ class << Tk::Tile::Style end def element_create(name, type, *args) - tk_call(TkCommandNames[0], 'element', 'create', name, type, *args) + if type == 'image' || type == :image + element_create_image(name, *args) + else + tk_call(TkCommandNames[0], 'element', 'create', name, type, *args) + end + end + + def element_create_image(name, *args) + fail ArgumentError, 'Must supply a base image' unless (spec = args.shift) + if (opts = args.shift) + if opts.kind_of?(Hash) + opts = _symbolkey2str(opts) + else + fail ArgumentError, 'bad option' + end + end + fail ArgumentError, 'too many arguments' unless args.empty? + + if spec.kind_of?(Array) + # probably, command format is tile 0.8+ (Tcl/Tk8.5+) style + if Tk::Tile::TILE_SPEC_VERSION_ID >= 8 + if opts + tk_call(TkCommandNames[0], + 'element', 'create', name, 'image', spec, opts) + else + tk_call(TkCommandNames[0], 'element', 'create', name, 'image', spec) + end + else + fail ArgumentError, 'illegal arguments' if opts.key?('map') + base = spec.shift + opts['map'] = spec + tk_call(TkCommandNames[0], + 'element', 'create', name, 'image', base, opts) + end + else + # probably, command format is tile 0.7.8 or older style + if Tk::Tile::TILE_SPEC_VERSION_ID >= 8 + spec = [spec, *(opts.delete('map'))] if opts.key?('map') + end + if opts + tk_call(TkCommandNames[0], + 'element', 'create', name, 'image', spec, opts) + else + tk_call(TkCommandNames[0], 'element', 'create', name, 'image', spec) + end + end end def element_names() diff --git a/ext/tk/lib/tkextlib/tile/treeview.rb b/ext/tk/lib/tkextlib/tile/treeview.rb index 36496ee0b..7f31b9c23 100644 --- a/ext/tk/lib/tkextlib/tile/treeview.rb +++ b/ext/tk/lib/tkextlib/tile/treeview.rb @@ -381,7 +381,7 @@ module Tk::Tile::TreeviewConfig when :item, 'item' ['width'] when :column, 'column' - super(id[1]) + super(id[1]) + ['minwidth'] when :tag, 'tag' super(id[1]) when :heading, 'heading' @@ -413,7 +413,7 @@ module Tk::Tile::TreeviewConfig when :item, 'item' ['open'] when :column, 'column' - super(id[1]) + super(id[1]) + ['stretch'] when :tag, 'tag' super(id[1]) when :heading, 'heading' @@ -617,30 +617,43 @@ end class Tk::Tile::Treeview::Item < TkObject ItemID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ Tk::Tile::Treeview::Item::ItemID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Item::ItemID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::Tile::Treeview::Item::ItemID_TBL[tpath] - (Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id])? \ - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]: id + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] + (Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id])? \ + Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]: id + else + id + end + } end def self.assign(tree, id) tpath = tree.path - if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] && - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] - return Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] - end + obj = nil + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] && + Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] + return Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] + end - obj = self.allocate - obj.instance_eval{ - @parent = @t = tree - @tpath = tpath - @path = @id = id + obj = self.allocate + obj.instance_eval{ + @parent = @t = tree + @tpath = tpath + @path = @id = id + } + Tk::Tile::Treeview::Item::ItemID_TBL[tpath] ||= {} + Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] = obj } - ItemID_TBL[tpath] = {} unless ItemID_TBL[tpath] - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] = obj obj end @@ -669,8 +682,10 @@ class Tk::Tile::Treeview::Item < TkObject @parent = @t = tree @tpath = tree.path @path = @id = _insert_item(@t, parent_item, idx, keys) - ItemID_TBL[@tpath] = {} unless ItemID_TBL[@tpath] - ItemID_TBL[@tpath][@id] = self + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + ItemID_TBL[@tpath] = {} unless ItemID_TBL[@tpath] + ItemID_TBL[@tpath][@id] = self + } end def id @id @@ -804,22 +819,35 @@ end class Tk::Tile::Treeview::Root < Tk::Tile::Treeview::Item def self.new(tree, keys = {}) tpath = tree.path - if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] && - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][''] - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][''] - else - super(tree, keys) - end + obj = nil + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] && + Tk::Tile::Treeview::Item::ItemID_TBL[tpath][''] + obj = Tk::Tile::Treeview::Item::ItemID_TBL[tpath][''] + else + #super(tree, keys) + (obj = self.allocate).instance_eval{ + @parent = @t = tree + @tpath = tree.path + @path = @id = '' + Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] ||= {} + Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self + } + end + } + obj.configure(keys) if keys && ! keys.empty? + obj end def initialize(tree, keys = {}) + # dummy:: not called by 'new' method @parent = @t = tree @tpath = tree.path @path = @id = '' - unless Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] - Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] = {} - end - Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] ||= {} + Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self + } end end @@ -829,24 +857,42 @@ class Tk::Tile::Treeview::Tag < TkObject include TkTreatTagFont TagID_TBL = TkCore::INTERP.create_table - Tag_ID = ['tile_treeview_tag'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ Tk::Tile::Treeview::Tag::TagID_TBL.clear } + (Tag_ID = ['tile_treeview_tag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + Tk::Tile::Treeview::Tag::TagID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Tag::TagID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::Tile::Treeview::Tag::TagID_TBL[tpath] - (Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id])? \ - Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id]: id + Tk::Tile::Treeview::Tag::TagID_TBL.mutex.synchronize{ + if Tk::Tile::Treeview::Tag::TagID_TBL[tpath] + (Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id])? \ + Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id]: id + else + id + end + } end def initialize(tree, keys=nil) @parent = @t = tree @tpath = tree.path - @path = @id = Tag_ID.join(TkCore::INTERP._ip_id_) - TagID_TBL[@tpath] = {} unless TagID_TBL[@tpath] - TagID_TBL[@tpath][@id] = self - Tag_ID[1].succ! + Tag_ID.mutex.synchronize{ + @path = @id = Tag_ID.join(TkCore::INTERP._ip_id_) + Tag_ID[1].succ! + } + TagID_TBL.mutex.synchronize{ + TagID_TBL[@tpath] = {} unless TagID_TBL[@tpath] + TagID_TBL[@tpath][@id] = self + } if keys && keys != None tk_call_without_enc(@tpath, 'tag', 'configure', *hash_kv(keys, true)) end @@ -919,8 +965,12 @@ class Tk::Tile::Treeview < TkWindow WidgetClassNames[WidgetClassName] = self def __destroy_hook__ - Tk::Tile::Treeview::Item::ItemID_TBL.delete(@path) - Tk::Tile::Treeview::Tag::ItemID_TBL.delete(@path) + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Item::ItemID_TBL.delete(@path) + } + Tk::Tile::Treeview::Tag::ItemID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Tag::ItemID_TBL.delete(@path) + } end def self.style(*args) diff --git a/ext/tk/lib/tkextlib/tkDND/tkdnd.rb b/ext/tk/lib/tkextlib/tkDND/tkdnd.rb index a040532eb..ea91d3d1f 100644 --- a/ext/tk/lib/tkextlib/tkDND/tkdnd.rb +++ b/ext/tk/lib/tkextlib/tkDND/tkdnd.rb @@ -57,6 +57,22 @@ module Tk nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + # setup tables _setup_subst_table(KEY_TBL, PROC_TBL); end diff --git a/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb b/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb index 8527f61df..d893a83cf 100644 --- a/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb +++ b/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb @@ -39,7 +39,10 @@ class Tk::HTML_Widget::ClippingWindow WidgetClassNames[WidgetClassName] = self HtmlClip_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ HtmlClip_TBL.clear } + + TkCore::INTERP.init_ip_env{ + HtmlClip_TBL.mutex.synchronize{ HtmlClip_TBL.clear } + } def self.new(parent, keys={}) if parent.kind_of?(Hash) @@ -54,7 +57,9 @@ class Tk::HTML_Widget::ClippingWindow else ppath = '' end - return HtmlClip_TBL[ppath] if HtmlClip_TBL[ppath] + HtmlClip_TBL.mutex.synchronize{ + return HtmlClip_TBL[ppath] if HtmlClip_TBL[ppath] + } widgetname = keys.delete('widgetname') if widgetname =~ /^(.*)\.[^.]+$/ @@ -62,7 +67,9 @@ class Tk::HTML_Widget::ClippingWindow if ppath2[0] != ?. ppath2 = ppath + '.' + ppath2 end - return HtmlClip_TBL[ppath2] if HtmlClip_TBL[ppath2] + HtmlClip_TBL.mutex.synchronize{ + return HtmlClip_TBL[ppath2] if HtmlClip_TBL[ppath2] + } ppath = ppath2 end @@ -79,7 +86,9 @@ class Tk::HTML_Widget::ClippingWindow @parent = parent @ppath = parent.path @path = @id = @ppath + '.x' - HtmlClip_TBL[@ppath] = self + HtmlClip_TBL.mutex.synchronize{ + HtmlClip_TBL[@ppath] = self + } end def method_missing(m, *args, &b) diff --git a/ext/tk/lib/tkextlib/tktable/tktable.rb b/ext/tk/lib/tkextlib/tktable/tktable.rb index 4edaabc84..fb8a8b0f7 100644 --- a/ext/tk/lib/tkextlib/tktable/tktable.rb +++ b/ext/tk/lib/tkextlib/tktable/tktable.rb @@ -118,23 +118,39 @@ class Tk::TkTable::CellTag include TkTreatTagFont CellTagID_TBL = TkCore::INTERP.create_table - CellTag_ID = ['tktbl:celltag'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ CellTagID_TBL.clear } + (CellTag_ID = ['tktbl:celltag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + CellTagID_TBL.mutex.synchronize{ CellTagID_TBL.clear } + } def self.id2obj(table, id) tpath = table.path - return id unless CellTagID_TBL[tpath] - CellTagID_TBL[tpath][id]? CellTagID_TBL[tpath][id] : id + CellTagID_TBL.mutex.synchronize{ + if CellTagID_TBL[tpath] + CellTagID_TBL[tpath][id]? CellTagID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, keys=nil) @parent = @t = parent @tpath - parent.path - @path = @id = CellTag_ID.join(TkCore::INTERP._ip_id_) - CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] - CellTagID_TBL[@tpath][@id] = self - CellTag_ID[1].succ! + CellTag_ID.mutex.synchronize{ + @path = @id = CellTag_ID.join(TkCore::INTERP._ip_id_) + CellTag_ID[1].succ! + } + CellTagID_TBL.mutex.synchronize{ + CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] + CellTagID_TBL[@tpath][@id] = self + } configure(keys) if keys end @@ -144,7 +160,9 @@ class Tk::TkTable::CellTag def destroy tk_call(@tpath, 'tag', 'delete', @id) - CellTagID_TBL[@tpath].delete(@id) if CellTagID_TBL[@tpath] + CellTagID_TBL.mutex.synchronize{ + CellTagID_TBL[@tpath].delete(@id) if CellTagID_TBL[@tpath] + } self end alias delete destroy @@ -189,22 +207,35 @@ end class Tk::TkTable::NamedCellTag < Tk::TkTable::CellTag def self.new(parent, name, keys=nil) - if CellTagID_TBL[parent.path] && CellTagID_TBL[parent.path][name] - cell = CellTagID_TBL[parent.path][name] - cell.configure(keys) if keys - return cell - else - super(parent, name, keys) - end + obj = nil + CellTagID_TBL.mutex.synchronize{ + if CellTagID_TBL[parent.path] && CellTagID_TBL[parent.path][name] + obj = CellTagID_TBL[parent.path][name] + else + #super(parent, name, keys) + (obj = self.allocate).instance_eval{ + @parent = @t = parent + @tpath = parent.path + @path = @id = name + CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] + CellTagID_TBL[@tpath][@id] = self + } + end + } + obj.configure(keys) if keys && ! keys.empty? + obj end def initialize(parent, name, keys=nil) + # dummy:: not called by 'new' method @parent = @t = parent - @tpath - parent.path + @tpath = parent.path @path = @id = name - CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] - CellTagID_TBL[@tpath][@id] = self - configure(keys) if keys + CellTagID_TBL.mutex.synchronize{ + CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] + CellTagID_TBL[@tpath][@id] = self + } + configure(keys) if keys && ! keys.empty? end end @@ -220,7 +251,9 @@ class Tk::TkTable include Tk::ValidateConfigure def __destroy_hook__ - Tk::TkTable::CelTag::CellTagID_TBL.delete(@path) + Tk::TkTable::CelTag::CellTagID_TBL.mutex.synchronize{ + Tk::TkTable::CelTag::CellTagID_TBL.delete(@path) + } end def __boolval_optkeys @@ -258,6 +291,22 @@ class Tk::TkTable nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -291,6 +340,22 @@ class Tk::TkTable nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -322,6 +387,22 @@ class Tk::TkTable nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -356,6 +437,22 @@ class Tk::TkTable nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); end @@ -746,15 +843,17 @@ class Tk::TkTable end def tagid2obj(tagid) - if Tk::TkTable::CellTag::CellTagID_TBL.key?(@path) - if Tk::TkTable::CellTag::CellTagID_TBL[@path].key?(tagid) - Tk::TkTable::CellTag::CellTagID_TBL[@path][tagid] + Tk::TkTable::CellTag::CellTagID_TBL.mutex.synchronize{ + if Tk::TkTable::CellTag::CellTagID_TBL.key?(@path) + if Tk::TkTable::CellTag::CellTagID_TBL[@path].key?(tagid) + Tk::TkTable::CellTag::CellTagID_TBL[@path][tagid] + else + tagid + end else tagid end - else - tagid - end + } end def tag_cell(tag, *cells) @@ -775,13 +874,15 @@ class Tk::TkTable end def tag_delete(tag) tk_send('tag', 'delete', tagid(tag)) - if Tk::TkTable::CellTag::CellTagID_TBL[@path] - if tag.kind_of? Tk::TkTable::CellTag - Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag.id) - else - Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag) + Tk::TkTable::CellTag::CellTagID_TBL.mutex.synchronize{ + if Tk::TkTable::CellTag::CellTagID_TBL[@path] + if tag.kind_of? Tk::TkTable::CellTag + Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag.id) + else + Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag) + end end - end + } self end def tag_exist?(tag) diff --git a/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb b/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb index 12f7cffab..b72b157dc 100644 --- a/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb +++ b/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb @@ -137,6 +137,22 @@ class Tk::TreeCtrl::NotifyEvent nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + # setup tables to be used by scan_args, _get_subst_key, _get_all_subst_keys # # _get_subst_key() and _get_all_subst_keys() generates key-string @@ -544,10 +560,18 @@ class Tk::TreeCtrl ######################### def __destroy_hook__ - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.delete(@path) - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.delete(@path) - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.delete(@path) - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.delete(@path) + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.delete(@path) + } + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.delete(@path) + } + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.delete(@path) + } + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.delete(@path) + } end ######################### @@ -638,9 +662,11 @@ class Tk::TreeCtrl end def column_delete(idx) - if Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path] - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path].delete(idx) - end + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path] + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path].delete(idx) + end + } tk_send('column', 'delete', idx) self end @@ -750,11 +776,13 @@ class Tk::TreeCtrl end def element_delete(*elems) - if Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path] - elems.each{|elem| - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path].delete(elem) - } - end + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path] + elems.each{|elem| + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path].delete(elem) + } + end + } tk_send('element', 'delete', *elems) self end @@ -885,22 +913,25 @@ class Tk::TreeCtrl def _erase_children(item) item_children(item).each{|i| _erase_children(i)} + # table is already locked Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path].delete(item) end private :_erase_children def item_delete(first, last=None) - if Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path] - if first == 'all' || first == :all || last == 'all' || last == :all - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path].clear - elsif last == None - _erase_children(first) - else - self.range(first, last).each{|id| - _erase_children(id) - } + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path] + if first == 'all' || first == :all || last == 'all' || last == :all + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path].clear + elsif last == None + _erase_children(first) + else + self.range(first, last).each{|id| + _erase_children(id) + } + end end - end + } tk_send('item', 'delete', first, last) self end @@ -1520,11 +1551,13 @@ class Tk::TreeCtrl end def style_delete(*args) - if Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path] - args.each{|sty| - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path].delete(sty) - } - end + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path] + args.each{|sty| + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path].delete(sty) + } + end + } tk_send('style', 'delete', *args) self end @@ -1608,15 +1641,29 @@ end class Tk::TreeCtrl::Column < TkObject TreeCtrlColumnID_TBL = TkCore::INTERP.create_table - TreeCtrlColumnID = ['treectrl_column'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.clear} + (TreeCtrlColumnID = ['treectrl_column'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath] - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id]? \ - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id] : id + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath] + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id]? \ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, keys={}) @@ -1625,17 +1672,19 @@ class Tk::TreeCtrl::Column < TkObject keys = _symbolkey2str(keys) - @path = @id = - keys.delete('tag') || - Tk::TreeCtrl::Column::TreeCtrlColumnID.join(TkCore::INTERP._ip_id_) + Tk::TreeCtrl::Column::TreeCtrlColumnID.mutex.synchronize{ + @path = @id = + keys.delete('tag') || + Tk::TreeCtrl::Column::TreeCtrlColumnID.join(TkCore::INTERP._ip_id_) + Tk::TreeCtrl::Column::TreeCtrlColumnID[1].succ! + } keys['tag'] = @id - unless Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath] - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath] = {} - end - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath][@id] = self - Tk::TreeCtrl::Column::TreeCtrlColumnID[1].succ! + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath] ||= {} + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath][@id] = self + } @tree.column_create(keys) end @@ -1692,11 +1741,18 @@ end class Tk::TreeCtrl::Element < TkObject TreeCtrlElementID_TBL = TkCore::INTERP.create_table - TreeCtrlElementID = ['treectrl_element'.freeze, '00000'.taint].freeze + + (TreeCtrlElementID = ['treectrl_element'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } TreeCtrlElemTypeToClass = {} TkCore::INTERP.init_ip_env{ - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.clear + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.clear + } } def self.type2class(type) @@ -1705,22 +1761,30 @@ class Tk::TreeCtrl::Element < TkObject def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath] - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath][id]? \ + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath] + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath][id]? \ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, type, keys=nil) @tree = parent @tpath = parent.path @type = type.to_s - @path = @id = - Tk::TreeCtrl::Element::TreeCtrlElementID.join(TkCore::INTERP._ip_id_) - unless Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath] - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath] = {} - end - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath][@id] = self - Tk::TreeCtrl::Element::TreeCtrlElementID[1].succ! + Tk::TreeCtrl::Element::TreeCtrlElementID.mutex.synchronize{ + @path = @id = + Tk::TreeCtrl::Element::TreeCtrlElementID.join(TkCore::INTERP._ip_id_) + Tk::TreeCtrl::Element::TreeCtrlElementID[1].succ! + } + + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath] ||= {} + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath][@id] = self + } @tree.element_create(@id, @type, keys) end @@ -1800,13 +1864,22 @@ end class Tk::TreeCtrl::Item < TkObject TreeCtrlItemID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.clear} + TkCore::INTERP.init_ip_env{ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath] - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id]? \ - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id] : id + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath] + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id]? \ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, keys={}) @@ -1814,10 +1887,10 @@ class Tk::TreeCtrl::Item < TkObject @tpath = parent.path @path = @id = @tree.item_create(keys) - unless Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath] - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath] = {} - end - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath][@id] = self + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath] ||= {} + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath][@id] = self + } end def id @@ -2088,27 +2161,45 @@ end class Tk::TreeCtrl::Style < TkObject TreeCtrlStyleID_TBL = TkCore::INTERP.create_table - TreeCtrlStyleID = ['treectrl_style'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.clear } + (TreeCtrlStyleID = ['treectrl_style'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath] - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id]? \ - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id] : id + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath] + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id]? \ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, keys=nil) @tree = parent @tpath = parent.path - @path = @id = - Tk::TreeCtrl::Style::TreeCtrlStyleID.join(TkCore::INTERP._ip_id_) - unless Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath] - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath] = {} - end - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath][@id] = self - Tk::TreeCtrl::Style::TreeCtrlStyleID[1].succ! + + Tk::TreeCtrl::Style::TreeCtrlStyleID.mutex.synchronize{ + @path = @id = + Tk::TreeCtrl::Style::TreeCtrlStyleID.join(TkCore::INTERP._ip_id_) + Tk::TreeCtrl::Style::TreeCtrlStyleID[1].succ! + } + + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath] ||= {} + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath][@id] = self + } @tree.style_create(@id, keys) end diff --git a/ext/tk/lib/tkextlib/version.rb b/ext/tk/lib/tkextlib/version.rb index c7816fd4a..3542c79db 100644 --- a/ext/tk/lib/tkextlib/version.rb +++ b/ext/tk/lib/tkextlib/version.rb @@ -2,5 +2,5 @@ # release date of tkextlib # module Tk - Tkextlib_RELEASE_DATE = '2007-05-26'.freeze + Tkextlib_RELEASE_DATE = '2008-03-29'.freeze end diff --git a/ext/tk/lib/tkextlib/vu/pie.rb b/ext/tk/lib/tkextlib/vu/pie.rb index 78f3fa54d..1975803db 100644 --- a/ext/tk/lib/tkextlib/vu/pie.rb +++ b/ext/tk/lib/tkextlib/vu/pie.rb @@ -116,13 +116,26 @@ end class Tk::Vu::PieSlice SliceID_TBL = TkCore::INTERP.create_table - Pie_Slice_ID = ['vu:pie'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ SliceID_TBL.clear } + + (Pie_Slice_ID = ['vu:pie'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + SliceID_TBL.mutex.synchronize{ SliceID_TBL.clear } + } def self.id2obj(pie, id) pie_path = pie.path - return id unless SliceID_TBL[pie_path] - SliceID_TBL[pie_path][id]? SliceID_TBL[pie_path][id]: id + SliceID_TBL.mutex.synchronize{ + if SliceID_TBL[pie_path] + SliceID_TBL[pie_path][id]? SliceID_TBL[pie_path][id]: id + else + id + end + } end def initialize(parent, *args) @@ -131,10 +144,14 @@ class Tk::Vu::PieSlice end @parent = @pie = parent @ppath = parent.path - @path = @id = Pie_Slice_ID.join(TkCore::INTERP._ip_id_) - SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] - SliceID_TBL[@ppath][@id] = self - Pie_Slice_ID[1].succ! + Pie_Slice_ID.mutex.synchronize{ + @path = @id = Pie_Slice_ID.join(TkCore::INTERP._ip_id_) + Pie_Slice_ID[1].succ! + } + SliceID_TBL.mutex.synchronize{ + SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] + SliceID_TBL[@ppath][@id] = self + } if args[-1].kind_of?(Hash) keys = args.unshift @@ -209,22 +226,48 @@ end class Tk::Vu::NamedPieSlice def self.new(parent, name, *args) - if SliceID_TBL[parent.path] && SliceID_TBL[parent.path][name] - return SliceID_TBL[parent.path][name] - else - super(parent, name, *args) - end + obj = nil + SliceID_TBL.mutex.synchronize{ + if SliceID_TBL[parent.path] && SliceID_TBL[parent.path][name] + obj = SliceID_TBL[parent.path][name] + else + #super(parent, name, *args) + unless parent.kind_of?(Tk::Vu::Pie) + fail ArgumentError, "expect a Tk::Vu::Pie instance for 1st argument" + end + obj = self.allocate + obj.instance_eval{ + @parent = @pie = parent + @ppath = parent.path + @path = @id = name.to_s + SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] + SliceID_TBL[@ppath][@id] = self + } + end + } + obj.instance_eval{ + if args[-1].kind_of?(Hash) + keys = args.unshift + end + @pie.set(@id, *args) + configure(keys) + } + + obj end def initialize(parent, name, *args) + # dummy:: not called by 'new' method unless parent.kind_of?(Tk::Vu::Pie) fail ArgumentError, "expect a Tk::Vu::Pie instance for 1st argument" end @parent = @pie = parent @ppath = parent.path @path = @id = name.to_s - SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] - SliceID_TBL[@ppath][@id] = self + SliceID_TBL.mutex.synchronize{ + SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] + SliceID_TBL[@ppath][@id] = self + } if args[-1].kind_of?(Hash) keys = args.unshift diff --git a/ext/tk/lib/tkextlib/winico/winico.rb b/ext/tk/lib/tkextlib/winico/winico.rb index c53a3ff48..30fb9682d 100644 --- a/ext/tk/lib/tkextlib/winico/winico.rb +++ b/ext/tk/lib/tkextlib/winico/winico.rb @@ -34,10 +34,15 @@ end class Tk::Winico WinicoID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ WinicoID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + WinicoID_TBL.mutex.synchronize{ WinicoID_TBL.clear } + } def self.id2obj(id) - (WinicoID_TBL.key?(id))? WinicoID_TBL[id] : id + WinicoID_TBL.mutex.synchronize{ + (WinicoID_TBL.key?(id))? WinicoID_TBL[id] : id + } end def self.info @@ -81,7 +86,9 @@ class Tk::Winico "must be given proper information from where loading icons" end @path = @id - WinicoID_TBL[@id] = self + WinicoID_TBL.mutex.synchronize{ + WinicoID_TBL[@id] = self + } end def id @@ -96,7 +103,9 @@ class Tk::Winico def delete tk_call('winico', 'delete', @id) - WinicoID_TBL.delete(@id) + WinicoID_TBL.mutex.synchronize{ + WinicoID_TBL.delete(@id) + } self end alias destroy delete @@ -126,15 +135,37 @@ class Tk::Winico [ ?n, TkComm.method(:number) ], [ ?s, TkComm.method(:string) ], [ ?x, proc{|id| - if Tk::Winico::WinicoID_TBL.key?(id) - Tk::Winico::WinicoID_TBL[id] - else - Tk::Winico.new(nil, nil, id) - end + Tk::Winico::WinicoID_TBL.mutex.synchronize{ + if Tk::Winico::WinicoID_TBL.key?(id) + obj = Tk::Winico::WinicoID_TBL[id] + else + # Tk::Winico.new(nil, nil, id) + obj = Tk::Winico.allocate + obj.instance_eval{ @path = @id = id } + Tk::Winico::WinicoID_TBL[id] = obj + end + obj + } } ], nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) |