1#
2#               tk.rb - Tk interface module using tcltklib
3#                       by Yukihiro Matsumoto <matz@netlab.jp>
4
5# use Shigehiro's tcltklib
6require 'tcltklib'
7require 'tkutil'
8
9# autoload
10require 'tk/autoload'
11
12# for Mutex
13require 'thread'
14
15class TclTkIp
16  # backup original (without encoding) _eval and _invoke
17  alias _eval_without_enc _eval
18  alias __eval__ _eval
19  alias _invoke_without_enc _invoke
20  alias __invoke__ _invoke
21
22  def _ip_id_
23    # for RemoteTkIp
24    ''
25  end
26
27  alias __initialize__ initialize
28  private :__initialize__
29
30  def initialize(*args)
31    __initialize__(*args)
32
33    @force_default_encoding ||= TkUtil.untrust([false])
34    @encoding ||= TkUtil.untrust([nil])
35    def @encoding.to_s; self.join(nil); end
36  end
37end
38
39# define TkComm module (step 1: basic functions)
40module TkComm
41  include TkUtil
42  extend TkUtil
43
44  WidgetClassNames = TkUtil.untrust({})
45  TkExtlibAutoloadModule = TkUtil.untrust([])
46
47  # None = Object.new  ### --> definition is moved to TkUtil module
48  # def None.to_s
49  #   'None'
50  # end
51  # None.freeze
52
53  #Tk_CMDTBL = {}
54  #Tk_WINDOWS = {}
55  Tk_IDs = [
56    TkUtil.untrust("00000"), # [0]-cmdid
57    TkUtil.untrust("00000")  # [1]-winid
58  ]
59  Tk_IDs.instance_eval{
60    @mutex = Mutex.new
61    def mutex; @mutex; end
62    freeze
63  }
64
65  # for backward compatibility
66  Tk_CMDTBL = Object.new
67  def Tk_CMDTBL.method_missing(id, *args)
68    TkCore::INTERP.tk_cmd_tbl.__send__(id, *args)
69  end
70  Tk_CMDTBL.freeze
71  Tk_WINDOWS = Object.new
72  def Tk_WINDOWS.method_missing(id, *args)
73    TkCore::INTERP.tk_windows.__send__(id, *args)
74  end
75  Tk_WINDOWS.freeze
76
77  self.instance_eval{
78    @cmdtbl = TkUtil.untrust([])
79  }
80
81  unless const_defined?(:GET_CONFIGINFO_AS_ARRAY)
82    # GET_CONFIGINFO_AS_ARRAY = false => returns a Hash { opt =>val, ... }
83    #                           true  => returns an Array [[opt,val], ... ]
84    # val is a list which includes resource info.
85    GET_CONFIGINFO_AS_ARRAY = true
86  end
87  unless const_defined?(:GET_CONFIGINFOwoRES_AS_ARRAY)
88    # for configinfo without resource info; list of [opt, value] pair
89    #           false => returns a Hash { opt=>val, ... }
90    #           true  => returns an Array [[opt,val], ... ]
91    GET_CONFIGINFOwoRES_AS_ARRAY = true
92  end
93  #  *** ATTENTION ***
94  # 'current_configinfo' method always returns a Hash under all cases of above.
95
96  def error_at
97    frames = caller()
98    frames.delete_if do |c|
99      c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+!
100    end
101    frames
102  end
103  private :error_at
104
105  def _genobj_for_tkwidget(path)
106    return TkRoot.new if path == '.'
107
108    begin
109      #tk_class = TkCore::INTERP._invoke('winfo', 'class', path)
110      tk_class = Tk.ip_invoke_without_enc('winfo', 'class', path)
111    rescue
112      return path
113    end
114
115    if ruby_class = WidgetClassNames[tk_class]
116      ruby_class_name = ruby_class.name
117      # gen_class_name = ruby_class_name + 'GeneratedOnTk'
118      gen_class_name = ruby_class_name
119      classname_def = ''
120    else # ruby_class == nil
121      if Tk.const_defined?(tk_class)
122        Tk.const_get(tk_class)  # auto_load
123        ruby_class = WidgetClassNames[tk_class]
124      end
125
126      unless ruby_class
127        mods = TkExtlibAutoloadModule.find_all{|m| m.const_defined?(tk_class)}
128        mods.each{|mod|
129          begin
130            mod.const_get(tk_class)  # auto_load
131            break if (ruby_class = WidgetClassNames[tk_class])
132          rescue LoadError
133            # ignore load error
134          end
135        }
136      end
137
138      unless ruby_class
139        std_class = 'Tk' << tk_class
140        if Object.const_defined?(std_class)
141          Object.const_get(std_class)  # auto_load
142          ruby_class = WidgetClassNames[tk_class]
143        end
144      end
145
146      unless ruby_class
147        if Tk.const_defined?('TOPLEVEL_ALIASES') &&
148            Tk::TOPLEVEL_ALIASES.const_defined?(std_class)
149          Tk::TOPLEVEL_ALIASES.const_get(std_class)  # auto_load
150          ruby_class = WidgetClassNames[tk_class]
151        end
152      end
153
154      if ruby_class
155        # found
156        ruby_class_name = ruby_class.name
157        gen_class_name = ruby_class_name
158        classname_def = ''
159      else
160        # unknown
161        ruby_class_name = 'TkWindow'
162        gen_class_name = 'TkWidget_' + tk_class
163        classname_def = "WidgetClassName = '#{tk_class}'.freeze"
164      end
165    end
166
167###################################
168=begin
169    if ruby_class = WidgetClassNames[tk_class]
170      ruby_class_name = ruby_class.name
171      # gen_class_name = ruby_class_name + 'GeneratedOnTk'
172      gen_class_name = ruby_class_name
173      classname_def = ''
174    else
175      mod = TkExtlibAutoloadModule.find{|m| m.const_defined?(tk_class)}
176      if mod
177        ruby_class_name = mod.name + '::' + tk_class
178        gen_class_name = ruby_class_name
179        classname_def = ''
180      elsif Object.const_defined?('Tk' + tk_class)
181        ruby_class_name = 'Tk' + tk_class
182        # gen_class_name = ruby_class_name + 'GeneratedOnTk'
183        gen_class_name = ruby_class_name
184        classname_def = ''
185      else
186        ruby_class_name = 'TkWindow'
187        # gen_class_name = ruby_class_name + tk_class + 'GeneratedOnTk'
188        gen_class_name = 'TkWidget_' + tk_class
189        classname_def = "WidgetClassName = '#{tk_class}'.freeze"
190      end
191    end
192=end
193
194=begin
195    unless Object.const_defined? gen_class_name
196      Object.class_eval "class #{gen_class_name}<#{ruby_class_name}
197                           #{classname_def}
198                         end"
199    end
200    Object.class_eval "#{gen_class_name}.new('widgetname'=>'#{path}',
201                                             'without_creating'=>true)"
202=end
203    base = Object
204    gen_class_name.split('::').each{|klass|
205      next if klass == ''
206      if base.const_defined?(klass)
207        base = base.class_eval klass
208      else
209        base = base.class_eval "class #{klass}<#{ruby_class_name}
210                                  #{classname_def}
211                                end
212                                #{klass}"
213      end
214    }
215    base.class_eval "#{gen_class_name}.new('widgetname'=>'#{path}',
216                                           'without_creating'=>true)"
217  end
218  private :_genobj_for_tkwidget
219  module_function :_genobj_for_tkwidget
220
221  def _at(x,y=nil)
222    if y
223      "@#{Integer(x)},#{Integer(y)}"
224    else
225      "@#{Integer(x)}"
226    end
227  end
228  module_function :_at
229
230  def tk_tcl2ruby(val, enc_mode = false, listobj = true)
231=begin
232    if val =~ /^rb_out\S* (c(_\d+_)?\d+)/
233      #return Tk_CMDTBL[$1]
234      return TkCore::INTERP.tk_cmd_tbl[$1]
235      #cmd_obj = TkCore::INTERP.tk_cmd_tbl[$1]
236      #if cmd_obj.kind_of?(Proc) || cmd_obj.kind_of?(Method)
237      #  cmd_obj
238      #else
239      #  cmd_obj.cmd
240      #end
241    end
242=end
243    if val =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/
244      return TkCore::INTERP.tk_cmd_tbl[$4]
245    end
246    #if val.include? ?\s
247    #  return val.split.collect{|v| tk_tcl2ruby(v)}
248    #end
249    case val
250    when /\A@font\S+\z/
251      TkFont.get_obj(val)
252    when /\A-?\d+\z/
253      val.to_i
254    when /\A\.\S*\z/
255      #Tk_WINDOWS[val] ? Tk_WINDOWS[val] : _genobj_for_tkwidget(val)
256      TkCore::INTERP.tk_windows[val]?
257           TkCore::INTERP.tk_windows[val] : _genobj_for_tkwidget(val)
258    when /\Ai(_\d+_)?\d+\z/
259      TkImage::Tk_IMGTBL.mutex.synchronize{
260        TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val
261      }
262    when /\A-?\d+\.?\d*(e[-+]?\d+)?\z/
263      val.to_f
264    when /\\ /
265      val.gsub(/\\ /, ' ')
266    when /[^\\] /
267      if listobj
268        #tk_split_escstr(val).collect{|elt|
269        #  tk_tcl2ruby(elt, enc_mode, listobj)
270        #}
271        val = _toUTF8(val) unless enc_mode
272        tk_split_escstr(val, false, false).collect{|elt|
273          tk_tcl2ruby(elt, true, listobj)
274        }
275      elsif enc_mode
276        _fromUTF8(val)
277      else
278        val
279      end
280    else
281      if enc_mode
282        _fromUTF8(val)
283      else
284        val
285      end
286    end
287  end
288
289  private :tk_tcl2ruby
290  module_function :tk_tcl2ruby
291  #private_class_method :tk_tcl2ruby
292
293unless const_defined?(:USE_TCLs_LIST_FUNCTIONS)
294  USE_TCLs_LIST_FUNCTIONS = true
295end
296
297if USE_TCLs_LIST_FUNCTIONS
298  ###########################################################################
299  # use Tcl function version of split_list
300  ###########################################################################
301
302  def tk_split_escstr(str, src_enc=true, dst_enc=true)
303    str = _toUTF8(str) if src_enc
304    if dst_enc
305      TkCore::INTERP._split_tklist(str).map!{|s| _fromUTF8(s)}
306    else
307      TkCore::INTERP._split_tklist(str)
308    end
309  end
310
311  def tk_split_sublist(str, depth=-1, src_enc=true, dst_enc=true)
312    # return [] if str == ""
313    # list = TkCore::INTERP._split_tklist(str)
314    str = _toUTF8(str) if src_enc
315
316    if depth == 0
317      return "" if str == ""
318      list = [str]
319    else
320      return [] if str == ""
321      list = TkCore::INTERP._split_tklist(str)
322    end
323    if list.size == 1
324      # tk_tcl2ruby(list[0], nil, false)
325      tk_tcl2ruby(list[0], dst_enc, false)
326    else
327      list.collect{|token| tk_split_sublist(token, depth - 1, false, dst_enc)}
328    end
329  end
330
331  def tk_split_list(str, depth=0, src_enc=true, dst_enc=true)
332    return [] if str == ""
333    str = _toUTF8(str) if src_enc
334    TkCore::INTERP._split_tklist(str).map!{|token|
335      tk_split_sublist(token, depth - 1, false, dst_enc)
336    }
337  end
338
339  def tk_split_simplelist(str, src_enc=true, dst_enc=true)
340    #lst = TkCore::INTERP._split_tklist(str)
341    #if (lst.size == 1 && lst =~ /^\{.*\}$/)
342    #  TkCore::INTERP._split_tklist(str[1..-2])
343    #else
344    #  lst
345    #end
346
347    str = _toUTF8(str) if src_enc
348    if dst_enc
349      TkCore::INTERP._split_tklist(str).map!{|s| _fromUTF8(s)}
350    else
351      TkCore::INTERP._split_tklist(str)
352    end
353  end
354
355  def array2tk_list(ary, enc=nil)
356    return "" if ary.size == 0
357
358    sys_enc = TkCore::INTERP.encoding
359    sys_enc = TclTkLib.encoding_system unless sys_enc
360
361    dst_enc = (enc == nil)? sys_enc: enc
362
363    dst = ary.collect{|e|
364      if e.kind_of? Array
365        s = array2tk_list(e, enc)
366      elsif e.kind_of? Hash
367        tmp_ary = []
368        #e.each{|k,v| tmp_ary << k << v }
369        e.each{|k,v| tmp_ary << "-#{_get_eval_string(k)}" << v }
370        s = array2tk_list(tmp_ary, enc)
371      else
372        s = _get_eval_string(e, enc)
373      end
374
375      if dst_enc != true && dst_enc != false
376        if (s_enc = s.instance_variable_get(:@encoding))
377          s_enc = s_enc.to_s
378        elsif TkCore::WITH_ENCODING
379          s_enc = s.encoding.name
380        else
381          s_enc = sys_enc
382        end
383        dst_enc = true if s_enc != dst_enc
384      end
385
386      s
387    }
388
389    if sys_enc && dst_enc
390      dst.map!{|s| _toUTF8(s)}
391      ret = TkCore::INTERP._merge_tklist(*dst)
392      if TkCore::WITH_ENCODING
393        if dst_enc.kind_of?(String)
394          ret = _fromUTF8(ret, dst_enc)
395          ret.force_encoding(dst_enc)
396        else
397          ret.force_encoding('utf-8')
398        end
399      else # without encoding
400        if dst_enc.kind_of?(String)
401          ret = _fromUTF8(ret, dst_enc)
402          ret.instance_variable_set(:@encoding, dst_enc)
403        else
404          ret.instance_variable_set(:@encoding, 'utf-8')
405        end
406      end
407      ret
408    else
409      TkCore::INTERP._merge_tklist(*dst)
410    end
411  end
412
413else
414  ###########################################################################
415  # use Ruby script version of split_list (traditional methods)
416  ###########################################################################
417
418  def tk_split_escstr(str, src_enc=true, dst_enc=true)
419    return [] if str == ""
420    list = []
421    token = nil
422    escape = false
423    brace = 0
424    str.split('').each {|c|
425      brace += 1 if c == '{' && !escape
426      brace -= 1 if c == '}' && !escape
427      if brace == 0 && c == ' ' && !escape
428        list << token.gsub(/^\{(.*)\}$/, '\1') if token
429        token = nil
430      else
431        token = (token || "") << c
432      end
433      escape = (c == '\\' && !escape)
434    }
435    list << token.gsub(/^\{(.*)\}$/, '\1') if token
436    list
437  end
438
439  def tk_split_sublist(str, depth=-1, src_enc=true, dst_enc=true)
440    #return [] if str == ""
441    #return [tk_split_sublist(str[1..-2])] if str =~ /^\{.*\}$/
442    #list = tk_split_escstr(str)
443    if depth == 0
444      return "" if str == ""
445      str = str[1..-2] if str =~ /^\{.*\}$/
446      list = [str]
447    else
448      return [] if str == []
449      return [tk_split_sublist(str[1..-2], depth - 1)] if str =~ /^\{.*\}$/
450      list = tk_split_escstr(str)
451    end
452    if list.size == 1
453      tk_tcl2ruby(list[0], nil, false)
454    else
455      list.collect{|token| tk_split_sublist(token, depth - 1)}
456    end
457  end
458
459  def tk_split_list(str, depth=0, src_enc=true, dst_enc=true)
460    return [] if str == ""
461    tk_split_escstr(str).collect{|token|
462      tk_split_sublist(token, depth - 1)
463    }
464  end
465
466  def tk_split_simplelist(str, src_enc=true, dst_enc=true)
467    return [] if str == ""
468    list = []
469    token = nil
470    escape = false
471    brace = 0
472    str.split('').each {|c|
473      if c == '\\' && !escape
474        escape = true
475        token = (token || "") << c if brace > 0
476        next
477      end
478      brace += 1 if c == '{' && !escape
479      brace -= 1 if c == '}' && !escape
480      if brace == 0 && c == ' ' && !escape
481        list << token.gsub(/^\{(.*)\}$/, '\1') if token
482        token = nil
483      else
484        token = (token || "") << c
485      end
486      escape = false
487    }
488    list << token.gsub(/^\{(.*)\}$/, '\1') if token
489    list
490  end
491
492  def array2tk_list(ary, enc=nil)
493    ary.collect{|e|
494      if e.kind_of? Array
495        "{#{array2tk_list(e, enc)}}"
496      elsif e.kind_of? Hash
497        # "{#{e.to_a.collect{|ee| array2tk_list(ee)}.join(' ')}}"
498        e.each{|k,v| tmp_ary << "-#{_get_eval_string(k)}" << v }
499        array2tk_list(tmp_ary, enc)
500      else
501        s = _get_eval_string(e, enc)
502        (s.index(/\s/) || s.size == 0)? "{#{s}}": s
503      end
504    }.join(" ")
505  end
506end
507
508  private :tk_split_escstr, :tk_split_sublist
509  private :tk_split_list, :tk_split_simplelist
510  private :array2tk_list
511
512  module_function :tk_split_escstr, :tk_split_sublist
513  module_function :tk_split_list, :tk_split_simplelist
514  module_function :array2tk_list
515
516  private_class_method :tk_split_escstr, :tk_split_sublist
517  private_class_method :tk_split_list, :tk_split_simplelist
518#  private_class_method :array2tk_list
519
520=begin
521  ### --> definition is moved to TkUtil module
522  def _symbolkey2str(keys)
523    h = {}
524    keys.each{|key,value| h[key.to_s] = value}
525    h
526  end
527  private :_symbolkey2str
528  module_function :_symbolkey2str
529=end
530
531=begin
532  ### --> definition is moved to TkUtil module
533  # def hash_kv(keys, enc_mode = nil, conf = [], flat = false)
534  def hash_kv(keys, enc_mode = nil, conf = nil)
535    # Hash {key=>val, key=>val, ... } or Array [ [key, val], [key, val], ... ]
536    #     ==> Array ['-key', val, '-key', val, ... ]
537    dst = []
538    if keys and keys != None
539      keys.each{|k, v|
540        #dst.push("-#{k}")
541        dst.push('-' + k.to_s)
542        if v != None
543          # v = _get_eval_string(v, enc_mode) if (enc_mode || flat)
544          v = _get_eval_string(v, enc_mode) if enc_mode
545          dst.push(v)
546        end
547      }
548    end
549    if conf
550      conf + dst
551    else
552      dst
553    end
554  end
555  private :hash_kv
556  module_function :hash_kv
557=end
558
559=begin
560  ### --> definition is moved to TkUtil module
561  def bool(val)
562    case val
563    when "1", 1, 'yes', 'true'
564      true
565    else
566      false
567    end
568  end
569
570  def number(val)
571    case val
572    when /^-?\d+$/
573      val.to_i
574    when /^-?\d+\.?\d*(e[-+]?\d+)?$/
575      val.to_f
576    else
577      fail(ArgumentError, "invalid value for Number:'#{val}'")
578    end
579  end
580  def string(val)
581    if val == "{}"
582      ''
583    elsif val[0] == ?{ && val[-1] == ?}
584      val[1..-2]
585    else
586      val
587    end
588  end
589  def num_or_str(val)
590    begin
591      number(val)
592    rescue ArgumentError
593      string(val)
594    end
595  end
596=end
597
598  def list(val, depth=0, enc=true)
599    tk_split_list(val, depth, enc, enc)
600  end
601  def simplelist(val, src_enc=true, dst_enc=true)
602    tk_split_simplelist(val, src_enc, dst_enc)
603  end
604  def window(val)
605    if val =~ /^\./
606      #Tk_WINDOWS[val]? Tk_WINDOWS[val] : _genobj_for_tkwidget(val)
607      TkCore::INTERP.tk_windows[val]?
608           TkCore::INTERP.tk_windows[val] : _genobj_for_tkwidget(val)
609    else
610      nil
611    end
612  end
613  def image_obj(val)
614    if val =~ /^i(_\d+_)?\d+$/
615      TkImage::Tk_IMGTBL.mutex.synchronize{
616        TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val
617      }
618    else
619      val
620    end
621  end
622  def procedure(val)
623=begin
624    if val =~ /^rb_out\S* (c(_\d+_)?\d+)/
625      #Tk_CMDTBL[$1]
626      #TkCore::INTERP.tk_cmd_tbl[$1]
627      TkCore::INTERP.tk_cmd_tbl[$1].cmd
628=end
629    if val =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/
630      return TkCore::INTERP.tk_cmd_tbl[$4].cmd
631    else
632      #nil
633      val
634    end
635  end
636  private :bool, :number, :num_or_str, :num_or_nil, :string
637  private :list, :simplelist, :window, :image_obj, :procedure
638  module_function :bool, :number, :num_or_str, :num_or_nil, :string
639  module_function :list, :simplelist, :window, :image_obj, :procedure
640
641  if (RUBY_VERSION.split('.').map{|n| n.to_i} <=> [1,8,7]) < 0
642    def slice_ary(ary, size)
643      sliced = []
644      wk_ary = ary.dup
645      until wk_ary.size.zero?
646        sub_ary = []
647        size.times{ sub_ary << wk_ary.shift }
648        yield(sub_ary) if block_given?
649        sliced << sub_ary
650      end
651      (block_given?)? ary: sliced
652    end
653  else
654    def slice_ary(ary, size, &b)
655      if b
656        ary.each_slice(size, &b)
657      else
658        ary.each_slice(size).to_a
659      end
660    end
661  end
662  private :slice_ary
663  module_function :slice_ary
664
665  def subst(str, *opts)
666    # opts := :nobackslashes | :nocommands | novariables
667    tk_call('subst',
668            *(opts.collect{|opt|
669                opt = opt.to_s
670                (opt[0] == ?-)? opt: '-' << opt
671              } << str))
672  end
673
674  def _toUTF8(str, encoding = nil)
675    TkCore::INTERP._toUTF8(str, encoding)
676  end
677  def _fromUTF8(str, encoding = nil)
678    TkCore::INTERP._fromUTF8(str, encoding)
679  end
680  private :_toUTF8, :_fromUTF8
681  module_function :_toUTF8, :_fromUTF8
682
683  def _callback_entry_class?(cls)
684    cls <= Proc || cls <= Method || cls <= TkCallbackEntry
685  end
686  private :_callback_entry_class?
687  module_function :_callback_entry_class?
688
689  def _callback_entry?(obj)
690    obj.kind_of?(Proc) || obj.kind_of?(Method) || obj.kind_of?(TkCallbackEntry)
691  end
692  private :_callback_entry?
693  module_function :_callback_entry?
694
695=begin
696  ### --> definition is moved to TkUtil module
697  def _get_eval_string(str, enc_mode = nil)
698    return nil if str == None
699    if str.kind_of?(TkObject)
700      str = str.path
701    elsif str.kind_of?(String)
702      str = _toUTF8(str) if enc_mode
703    elsif str.kind_of?(Symbol)
704      str = str.id2name
705      str = _toUTF8(str) if enc_mode
706    elsif str.kind_of?(Hash)
707      str = hash_kv(str, enc_mode).join(" ")
708    elsif str.kind_of?(Array)
709      str = array2tk_list(str)
710      str = _toUTF8(str) if enc_mode
711    elsif str.kind_of?(Proc)
712      str = install_cmd(str)
713    elsif str == nil
714      str = ""
715    elsif str == false
716      str = "0"
717    elsif str == true
718      str = "1"
719    elsif (str.respond_to?(:to_eval))
720      str = str.to_eval()
721      str = _toUTF8(str) if enc_mode
722    else
723      str = str.to_s() || ''
724      unless str.kind_of? String
725        fail RuntimeError, "fail to convert the object to a string"
726      end
727      str = _toUTF8(str) if enc_mode
728    end
729    return str
730  end
731=end
732=begin
733  def _get_eval_string(obj, enc_mode = nil)
734    case obj
735    when Numeric
736      obj.to_s
737    when String
738      (enc_mode)? _toUTF8(obj): obj
739    when Symbol
740      (enc_mode)? _toUTF8(obj.id2name): obj.id2name
741    when TkObject
742      obj.path
743    when Hash
744      hash_kv(obj, enc_mode).join(' ')
745    when Array
746      (enc_mode)? _toUTF8(array2tk_list(obj)): array2tk_list(obj)
747    when Proc, Method, TkCallbackEntry
748      install_cmd(obj)
749    when false
750      '0'
751    when true
752      '1'
753    when nil
754      ''
755    when None
756      nil
757    else
758      if (obj.respond_to?(:to_eval))
759        (enc_mode)? _toUTF8(obj.to_eval): obj.to_eval
760      else
761        begin
762          obj = obj.to_s || ''
763        rescue
764          fail RuntimeError, "fail to convert object '#{obj}' to string"
765        end
766        (enc_mode)? _toUTF8(obj): obj
767      end
768    end
769  end
770  private :_get_eval_string
771  module_function :_get_eval_string
772=end
773
774=begin
775  ### --> definition is moved to TkUtil module
776  def _get_eval_enc_str(obj)
777    return obj if obj == None
778    _get_eval_string(obj, true)
779  end
780  private :_get_eval_enc_str
781  module_function :_get_eval_enc_str
782=end
783
784=begin
785  ### --> obsolete
786  def ruby2tcl(v, enc_mode = nil)
787    if v.kind_of?(Hash)
788      v = hash_kv(v)
789      v.flatten!
790      v.collect{|e|ruby2tcl(e, enc_mode)}
791    else
792      _get_eval_string(v, enc_mode)
793    end
794  end
795  private :ruby2tcl
796=end
797
798=begin
799  ### --> definition is moved to TkUtil module
800  def _conv_args(args, enc_mode, *src_args)
801    conv_args = []
802    src_args.each{|arg|
803      conv_args << _get_eval_string(arg, enc_mode) unless arg == None
804      # if arg.kind_of?(Hash)
805      # arg.each{|k, v|
806      #   args << '-' + k.to_s
807      #   args << _get_eval_string(v, enc_mode)
808      # }
809      # elsif arg != None
810      #   args << _get_eval_string(arg, enc_mode)
811      # end
812    }
813    args + conv_args
814  end
815  private :_conv_args
816=end
817
818  def _curr_cmd_id
819    #id = format("c%.4d", Tk_IDs[0])
820    id = "c" + TkCore::INTERP._ip_id_ + TkComm::Tk_IDs[0]
821  end
822  def _next_cmd_id
823    TkComm::Tk_IDs.mutex.synchronize{
824      id = _curr_cmd_id
825      #Tk_IDs[0] += 1
826      TkComm::Tk_IDs[0].succ!
827      id
828    }
829  end
830  private :_curr_cmd_id, :_next_cmd_id
831  module_function :_curr_cmd_id, :_next_cmd_id
832
833  def TkComm.install_cmd(cmd, local_cmdtbl=nil)
834    return '' if cmd == ''
835    begin
836      ns = TkCore::INTERP._invoke_without_enc('namespace', 'current')
837      ns = nil if ns == '::' # for backward compatibility
838    rescue
839      # probably, Tcl7.6
840      ns = nil
841    end
842    id = _next_cmd_id
843    #Tk_CMDTBL[id] = cmd
844    if cmd.kind_of?(TkCallbackEntry)
845      TkCore::INTERP.tk_cmd_tbl[id] = cmd
846    else
847      TkCore::INTERP.tk_cmd_tbl[id] = TkCore::INTERP.get_cb_entry(cmd)
848    end
849    @cmdtbl = [] unless defined? @cmdtbl
850    TkUtil.untrust(@cmdtbl) unless @cmdtbl.tainted?
851    @cmdtbl.push id
852
853    if local_cmdtbl && local_cmdtbl.kind_of?(Array)
854      begin
855        local_cmdtbl << id
856      rescue Exception
857        # ignore
858      end
859    end
860
861    #return Kernel.format("rb_out %s", id);
862    if ns
863      'rb_out' << TkCore::INTERP._ip_id_ << ' ' << ns << ' ' << id
864    else
865      'rb_out' << TkCore::INTERP._ip_id_ << ' ' << id
866    end
867  end
868  def TkComm.uninstall_cmd(id, local_cmdtbl=nil)
869    #id = $1 if /rb_out\S* (c(_\d+_)?\d+)/ =~ id
870    id = $4 if id =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/
871
872    if local_cmdtbl && local_cmdtbl.kind_of?(Array)
873      begin
874        local_cmdtbl.delete(id)
875      rescue Exception
876        # ignore
877      end
878    end
879    @cmdtbl.delete(id)
880
881    #Tk_CMDTBL.delete(id)
882    TkCore::INTERP.tk_cmd_tbl.delete(id)
883  end
884  # private :install_cmd, :uninstall_cmd
885  # module_function :install_cmd, :uninstall_cmd
886  def install_cmd(cmd)
887    TkComm.install_cmd(cmd, @cmdtbl)
888  end
889  def uninstall_cmd(id)
890    TkComm.uninstall_cmd(id, @cmdtbl)
891  end
892
893=begin
894  def install_win(ppath,name=nil)
895    if !name or name == ''
896      #name = format("w%.4d", Tk_IDs[1])
897      #Tk_IDs[1] += 1
898      name = "w" + Tk_IDs[1]
899      Tk_IDs[1].succ!
900    end
901    if name[0] == ?.
902      @path = name.dup
903    elsif !ppath or ppath == "."
904      @path = Kernel.format(".%s", name);
905    else
906      @path = Kernel.format("%s.%s", ppath, name)
907    end
908    #Tk_WINDOWS[@path] = self
909    TkCore::INTERP.tk_windows[@path] = self
910  end
911=end
912  def install_win(ppath,name=nil)
913    if name
914      if name == ''
915        raise ArgumentError, "invalid wiget-name '#{name}'"
916      end
917      if name[0] == ?.
918        @path = '' + name
919        @path.freeze
920        return TkCore::INTERP.tk_windows[@path] = self
921      end
922    else
923      Tk_IDs.mutex.synchronize{
924        name = "w" + TkCore::INTERP._ip_id_ + Tk_IDs[1]
925        Tk_IDs[1].succ!
926      }
927    end
928    if !ppath or ppath == '.'
929      @path = '.' + name
930    else
931      @path = ppath + '.' + name
932    end
933    @path.freeze
934    TkCore::INTERP.tk_windows[@path] = self
935  end
936
937  def uninstall_win()
938    #Tk_WINDOWS.delete(@path)
939    TkCore::INTERP.tk_windows.delete(@path)
940  end
941  private :install_win, :uninstall_win
942
943  def _epath(win)
944    if win.kind_of?(TkObject)
945      win.epath
946    elsif win.respond_to?(:epath)
947      win.epath
948    else
949      win
950    end
951  end
952  private :_epath
953end
954
955# define TkComm module (step 2: event binding)
956module TkComm
957  include TkEvent
958  extend TkEvent
959
960  def tk_event_sequence(context)
961    if context.kind_of? TkVirtualEvent
962      context = context.path
963    end
964    if context.kind_of? Array
965      context = context.collect{|ev|
966        if ev.kind_of? TkVirtualEvent
967          ev.path
968        else
969          ev
970        end
971      }.join("><")
972    end
973    if /,/ =~ context
974      context = context.split(/\s*,\s*/).join("><")
975    else
976      context
977    end
978  end
979
980  def _bind_core(mode, what, context, cmd, *args)
981    id = install_bind(cmd, *args) if cmd
982    begin
983      tk_call_without_enc(*(what + ["<#{tk_event_sequence(context)}>",
984                              mode + id]))
985    rescue
986      uninstall_cmd(id) if cmd
987      fail
988    end
989  end
990
991  def _bind(what, context, cmd, *args)
992    _bind_core('', what, context, cmd, *args)
993  end
994
995  def _bind_append(what, context, cmd, *args)
996    _bind_core('+', what, context, cmd, *args)
997  end
998
999  def _bind_remove(what, context)
1000    tk_call_without_enc(*(what + ["<#{tk_event_sequence(context)}>", '']))
1001  end
1002
1003  def _bindinfo(what, context=nil)
1004    if context
1005      if TkCore::WITH_RUBY_VM  ### Ruby 1.9 !!!!
1006        enum_obj = tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]).each_line
1007      else
1008        enum_obj = tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"])
1009      end
1010      enum_obj.collect {|cmdline|
1011=begin
1012        if cmdline =~ /^rb_out\S* (c(?:_\d+_)?\d+)\s+(.*)$/
1013          #[Tk_CMDTBL[$1], $2]
1014          [TkCore::INTERP.tk_cmd_tbl[$1], $2]
1015=end
1016        if cmdline =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/
1017          [TkCore::INTERP.tk_cmd_tbl[$4], $5]
1018        else
1019          cmdline
1020        end
1021      }
1022    else
1023      tk_split_simplelist(tk_call_without_enc(*what)).collect!{|seq|
1024        l = seq.scan(/<*[^<>]+>*/).collect!{|subseq|
1025          case (subseq)
1026          when /^<<[^<>]+>>$/
1027            TkVirtualEvent.getobj(subseq[1..-2])
1028          when /^<[^<>]+>$/
1029            subseq[1..-2]
1030          else
1031            subseq.split('')
1032          end
1033        }.flatten
1034        (l.size == 1) ? l[0] : l
1035      }
1036    end
1037  end
1038
1039  def _bind_core_for_event_class(klass, mode, what, context, cmd, *args)
1040    id = install_bind_for_event_class(klass, cmd, *args) if cmd
1041    begin
1042      tk_call_without_enc(*(what + ["<#{tk_event_sequence(context)}>",
1043                              mode + id]))
1044    rescue
1045      uninstall_cmd(id) if cmd
1046      fail
1047    end
1048  end
1049
1050  def _bind_for_event_class(klass, what, context, cmd, *args)
1051    _bind_core_for_event_class(klass, '', what, context, cmd, *args)
1052  end
1053
1054  def _bind_append_for_event_class(klass, what, context, cmd, *args)
1055    _bind_core_for_event_class(klass, '+', what, context, cmd, *args)
1056  end
1057
1058  def _bind_remove_for_event_class(klass, what, context)
1059    _bind_remove(what, context)
1060  end
1061
1062  def _bindinfo_for_event_class(klass, what, context=nil)
1063    _bindinfo(what, context)
1064  end
1065
1066  private :tk_event_sequence
1067  private :_bind_core, :_bind, :_bind_append, :_bind_remove, :_bindinfo
1068  private :_bind_core_for_event_class, :_bind_for_event_class,
1069          :_bind_append_for_event_class, :_bind_remove_for_event_class,
1070          :_bindinfo_for_event_class
1071
1072  #def bind(tagOrClass, context, cmd=Proc.new, *args)
1073  #  _bind(["bind", tagOrClass], context, cmd, *args)
1074  #  tagOrClass
1075  #end
1076  def bind(tagOrClass, context, *args)
1077    # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
1078    if TkComm._callback_entry?(args[0]) || !block_given?
1079      cmd = args.shift
1080    else
1081      cmd = Proc.new
1082    end
1083    _bind(["bind", tagOrClass], context, cmd, *args)
1084    tagOrClass
1085  end
1086
1087  #def bind_append(tagOrClass, context, cmd=Proc.new, *args)
1088  #  _bind_append(["bind", tagOrClass], context, cmd, *args)
1089  #  tagOrClass
1090  #end
1091  def bind_append(tagOrClass, context, *args)
1092    # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
1093    if TkComm._callback_entry?(args[0]) || !block_given?
1094      cmd = args.shift
1095    else
1096      cmd = Proc.new
1097    end
1098    _bind_append(["bind", tagOrClass], context, cmd, *args)
1099    tagOrClass
1100  end
1101
1102  def bind_remove(tagOrClass, context)
1103    _bind_remove(['bind', tagOrClass], context)
1104    tagOrClass
1105  end
1106
1107  def bindinfo(tagOrClass, context=nil)
1108    _bindinfo(['bind', tagOrClass], context)
1109  end
1110
1111  #def bind_all(context, cmd=Proc.new, *args)
1112  #  _bind(['bind', 'all'], context, cmd, *args)
1113  #  TkBindTag::ALL
1114  #end
1115  def bind_all(context, *args)
1116    # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
1117    if TkComm._callback_entry?(args[0]) || !block_given?
1118      cmd = args.shift
1119    else
1120      cmd = Proc.new
1121    end
1122    _bind(['bind', 'all'], context, cmd, *args)
1123    TkBindTag::ALL
1124  end
1125
1126  #def bind_append_all(context, cmd=Proc.new, *args)
1127  #  _bind_append(['bind', 'all'], context, cmd, *args)
1128  #  TkBindTag::ALL
1129  #end
1130  def bind_append_all(context, *args)
1131    # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
1132    if TkComm._callback_entry?(args[0]) || !block_given?
1133      cmd = args.shift
1134    else
1135      cmd = Proc.new
1136    end
1137    _bind_append(['bind', 'all'], context, cmd, *args)
1138    TkBindTag::ALL
1139  end
1140
1141  def bind_remove_all(context)
1142    _bind_remove(['bind', 'all'], context)
1143    TkBindTag::ALL
1144  end
1145
1146  def bindinfo_all(context=nil)
1147    _bindinfo(['bind', 'all'], context)
1148  end
1149end
1150
1151
1152module TkCore
1153  include TkComm
1154  extend TkComm
1155
1156  WITH_RUBY_VM  = Object.const_defined?(:RubyVM) && ::RubyVM.class == Class
1157  WITH_ENCODING = defined?(::Encoding.default_external) && true
1158  #WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class
1159
1160  unless self.const_defined? :INTERP
1161    if self.const_defined? :IP_NAME
1162      name = IP_NAME.to_s
1163    else
1164      #name = nil
1165      name = $0
1166    end
1167    if self.const_defined? :IP_OPTS
1168      if IP_OPTS.kind_of?(Hash)
1169        opts = hash_kv(IP_OPTS).join(' ')
1170      else
1171        opts = IP_OPTS.to_s
1172      end
1173    else
1174      opts = ''
1175    end
1176
1177    # RUN_EVENTLOOP_ON_MAIN_THREAD = true
1178
1179    unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD
1180      if WITH_RUBY_VM ### check Ruby 1.9 !!!!!!!
1181        # *** NEED TO FIX ***
1182        case RUBY_PLATFORM
1183        when /cygwin/
1184          RUN_EVENTLOOP_ON_MAIN_THREAD = true
1185        when /darwin/ # MacOS X
1186=begin
1187          ip = TclTkIp.new(name, opts)
1188          if ip._invoke_without_enc('tk', 'windowingsystem') == 'aqua' &&
1189             (TclTkLib.get_version<=>[8,4,TclTkLib::RELEASE_TYPE::FINAL,6]) > 0
1190=end
1191          if TclTkLib::WINDOWING_SYSTEM == 'aqua' &&
1192             (TclTkLib.get_version<=>[8,4,TclTkLib::RELEASE_TYPE::FINAL,6]) > 0
1193            # *** KNOWN BUG ***
1194            #  Main event loop thread of TkAqua (> Tk8.4.9) must be the main
1195            #  application thread. So, ruby1.9 users must call Tk.mainloop on
1196            #  the main application thread.
1197            #
1198            # *** ADD (2009/05/10) ***
1199            #  In some cases (I don't know the description of conditions),
1200            #  TkAqua 8.4.7 has a same kind of hang-up trouble.
1201            #  So, if 8.4.7 or later, set RUN_EVENTLOOP_ON_MAIN_THREAD to true.
1202            #  When you want to control this mode, please call the following
1203            #  (set true/false as you want) before "require 'tk'".
1204            #  ----------------------------------------------------------
1205            #  module TkCore; RUN_EVENTLOOP_ON_MAIN_THREAD = true; end
1206            #  ----------------------------------------------------------
1207            #
1208            # *** ADD (2010/07/05) ***
1209            #  The value of TclTkLib::WINDOWING_SYSTEM is defined at compiling.
1210            #  If it is inconsistent with linked DLL, please call the following
1211            #  before "require 'tk'".
1212            #  ----------------------------------------------------------
1213            #  require 'tcltklib'
1214            #  module TclTkLib
1215            #    remove_const :WINDOWING_SYSTEM
1216            #    WINDOWING_SYSTEM = 'x11' # or 'aqua'
1217            #  end
1218            #  ----------------------------------------------------------
1219            #
1220            RUN_EVENTLOOP_ON_MAIN_THREAD = true
1221          else
1222            RUN_EVENTLOOP_ON_MAIN_THREAD = false
1223=begin
1224            ip.delete
1225            ip = nil
1226=end
1227          end
1228        else
1229          RUN_EVENTLOOP_ON_MAIN_THREAD = false
1230        end
1231
1232      else # Ruby 1.8.x
1233        RUN_EVENTLOOP_ON_MAIN_THREAD = false
1234      end
1235    end
1236
1237    if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!!
1238      INTERP = TclTkIp.new(name, opts) unless self.const_defined? :INTERP
1239    else
1240      INTERP_MUTEX = Mutex.new
1241      INTERP_ROOT_CHECK = ConditionVariable.new
1242      INTERP_THREAD = Thread.new{
1243        begin
1244          #Thread.current[:interp] = interp = TclTkIp.new(name, opts)
1245          interp = TclTkIp.new(name, opts)
1246        rescue => e
1247          Thread.current[:interp] = e
1248          raise e
1249        end
1250
1251        interp.mainloop_abort_on_exception = true
1252        Thread.current.instance_variable_set("@interp", interp)
1253
1254        status = [nil]
1255        def status.value
1256          self[0]
1257        end
1258        def status.value=(val)
1259          self[0] = val
1260        end
1261
1262        Thread.current[:status] = status
1263        #sleep
1264
1265        # like as 1.8, withdraw a root widget before calling Tk.mainloop
1266        interp._eval <<EOS
1267wm withdraw .
1268rename wm __wm_orig__
1269proc wm {subcmd win args} {
1270  set val [eval [list __wm_orig__ $subcmd $win] $args]
1271  if {[string equal $subcmd withdraw] && [string equal $win .]} {
1272    rename wm {}
1273    rename __wm_orig__ wm
1274  }
1275  return $val
1276}
1277proc __startup_rbtk_mainloop__ {args} {
1278  rename __startup_rbtk_mainloop__ {}
1279  if {[info command __wm_orig__] == "__wm_orig__"} {
1280    rename wm {}
1281    rename __wm_orig__ wm
1282    if [string equal [wm state .] withdrawn] {
1283      wm deiconify .
1284    }
1285  }
1286}
1287set __initial_state_of_rubytk__ 1
1288trace add variable __initial_state_of_rubytk__ unset __startup_rbtk_mainloop__
1289
1290# complete initializing
1291ruby {TkCore::INTERP_THREAD[:interp] = TkCore::INTERP_THREAD.instance_variable_get('@interp')}
1292EOS
1293
1294        begin
1295          begin
1296            #TclTkLib.mainloop_abort_on_exception = false
1297            #interp.mainloop_abort_on_exception = true
1298            #Thread.current[:interp] = interp
1299            #Thread.current[:status].value = TclTkLib.mainloop(true)
1300            Thread.current[:status].value = interp.mainloop(true)
1301          rescue SystemExit=>e
1302            Thread.current[:status].value = e
1303          rescue Exception=>e
1304            Thread.current[:status].value = e
1305            p e if $DEBUG
1306            retry if interp.has_mainwindow?
1307          ensure
1308            INTERP_MUTEX.synchronize{ INTERP_ROOT_CHECK.broadcast }
1309          end
1310
1311          unless interp.deleted?
1312            #Thread.current[:status].value = TclTkLib.mainloop(false)
1313            Thread.current[:status].value = interp.mainloop(false)
1314          end
1315
1316        ensure
1317          # interp must be deleted before the thread for interp is dead.
1318          # If not, raise Tcl_Panic on Tcl_AsyncDelete because async handler
1319          # deleted by the wrong thread.
1320          interp.delete
1321        end
1322      }
1323
1324      # check a Tcl/Tk interpreter is initialized
1325      until INTERP_THREAD[:interp]
1326        # Thread.pass
1327        INTERP_THREAD.run
1328      end
1329
1330      # INTERP_THREAD.run
1331      raise INTERP_THREAD[:interp] if INTERP_THREAD[:interp].kind_of? Exception
1332
1333      # check an eventloop is running
1334      while INTERP_THREAD.alive? && TclTkLib.mainloop_thread?.nil?
1335        INTERP_THREAD.run
1336      end
1337
1338      INTERP = INTERP_THREAD[:interp]
1339      INTERP_THREAD_STATUS = INTERP_THREAD[:status]
1340
1341      # delete the interpreter and kill the eventloop thread at exit
1342      END{
1343        if INTERP_THREAD.alive?
1344          INTERP.delete
1345          INTERP_THREAD.kill
1346        end
1347      }
1348
1349      # (for safety's sake) force the eventloop to run
1350      INTERP_THREAD.run
1351    end
1352
1353    def INTERP.__getip
1354      self
1355    end
1356    def INTERP.default_master?
1357      true
1358    end
1359
1360    INTERP.instance_eval{
1361      # @tk_cmd_tbl = TkUtil.untrust({})
1362      @tk_cmd_tbl =
1363        TkUtil.untrust(Hash.new{|hash, key|
1364                         fail IndexError, "unknown command ID '#{key}'"
1365                       })
1366      def @tk_cmd_tbl.[]=(idx,val)
1367        if self.has_key?(idx) && Thread.current.group != ThreadGroup::Default
1368          fail SecurityError,"cannot change the entried command"
1369        end
1370        super(idx,val)
1371      end
1372
1373      @tk_windows = TkUtil.untrust({})
1374
1375      @tk_table_list = TkUtil.untrust([])
1376
1377      @init_ip_env  = TkUtil.untrust([])  # table of Procs
1378      @add_tk_procs = TkUtil.untrust([])  # table of [name, args, body]
1379
1380      @force_default_encoding ||= TkUtil.untrust([false])
1381      @encoding ||= TkUtil.untrust([nil])
1382      def @encoding.to_s; self.join(nil); end
1383
1384      @cb_entry_class = Class.new(TkCallbackEntry){
1385        class << self
1386          def inspect
1387            sprintf("#<Class(TkCallbackEntry):%0x>", self.__id__)
1388          end
1389          alias to_s inspect
1390        end
1391
1392        def initialize(ip, cmd)
1393          @ip = ip
1394          @cmd = cmd
1395        end
1396        attr_reader :ip, :cmd
1397        def call(*args)
1398          @ip.cb_eval(@cmd, *args)
1399        end
1400        def inspect
1401          sprintf("#<cb_entry:%0x>", self.__id__)
1402        end
1403        alias to_s inspect
1404      }.freeze
1405    }
1406
1407    def INTERP.cb_entry_class
1408      @cb_entry_class
1409    end
1410    def INTERP.tk_cmd_tbl
1411      @tk_cmd_tbl
1412    end
1413    def INTERP.tk_windows
1414      @tk_windows
1415    end
1416
1417    class Tk_OBJECT_TABLE
1418      def initialize(id)
1419        @id = id
1420        @mutex = Mutex.new
1421      end
1422      def mutex
1423        @mutex
1424      end
1425      def method_missing(m, *args, &b)
1426        TkCore::INTERP.tk_object_table(@id).__send__(m, *args, &b)
1427      end
1428    end
1429
1430    def INTERP.tk_object_table(id)
1431      @tk_table_list[id]
1432    end
1433    def INTERP.create_table
1434      id = @tk_table_list.size
1435      (tbl = {}).tainted? || TkUtil.untrust(tbl)
1436      @tk_table_list << tbl
1437#      obj = Object.new
1438#      obj.instance_eval <<-EOD
1439#        def self.method_missing(m, *args)
1440#         TkCore::INTERP.tk_object_table(#{id}).send(m, *args)
1441#        end
1442#      EOD
1443#      return obj
1444      Tk_OBJECT_TABLE.new(id)
1445    end
1446
1447    def INTERP.get_cb_entry(cmd)
1448      @cb_entry_class.new(__getip, cmd).freeze
1449    end
1450    def INTERP.cb_eval(cmd, *args)
1451      TkUtil._get_eval_string(TkUtil.eval_cmd(cmd, *args))
1452    end
1453
1454    def INTERP.init_ip_env(script = Proc.new)
1455      @init_ip_env << script
1456      script.call(self)
1457    end
1458    def INTERP.add_tk_procs(name, args = nil, body = nil)
1459      if name.kind_of?(Array)
1460        name.each{|param| self.add_tk_procs(*param)}
1461      else
1462        name = name.to_s
1463        @add_tk_procs << [name, args, body]
1464        self._invoke('proc', name, args, body) if args && body
1465      end
1466    end
1467    def INTERP.remove_tk_procs(*names)
1468      names.each{|name|
1469        name = name.to_s
1470        @add_tk_procs.delete_if{|elem|
1471          elem.kind_of?(Array) && elem[0].to_s == name
1472        }
1473        #self._invoke('rename', name, '')
1474        self.__invoke__('rename', name, '')
1475      }
1476    end
1477    def INTERP.init_ip_internal
1478      ip = self
1479      @init_ip_env.each{|script| script.call(ip)}
1480      @add_tk_procs.each{|name,args,body| ip._invoke('proc',name,args,body)}
1481    end
1482  end
1483
1484  unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD
1485    ### Ruby 1.9 !!!!!!!!!!!!!!!!!!!!!!!!!!
1486    RUN_EVENTLOOP_ON_MAIN_THREAD = false
1487  end
1488
1489  WIDGET_DESTROY_HOOK = '<WIDGET_DESTROY_HOOK>'
1490  INTERP._invoke_without_enc('event', 'add',
1491                             "<#{WIDGET_DESTROY_HOOK}>", '<Destroy>')
1492  INTERP._invoke_without_enc('bind', 'all', "<#{WIDGET_DESTROY_HOOK}>",
1493                             install_cmd(proc{|path|
1494                                unless TkCore::INTERP.deleted?
1495                                  begin
1496                                    if (widget=TkCore::INTERP.tk_windows[path])
1497                                      if widget.respond_to?(:__destroy_hook__)
1498                                        widget.__destroy_hook__
1499                                      end
1500                                    end
1501                                  rescue Exception=>e
1502                                      p e if $DEBUG
1503                                  end
1504                                end
1505                             }) << ' %W')
1506
1507  INTERP.add_tk_procs(TclTkLib::FINALIZE_PROC_NAME, '',
1508                      "catch { bind all <#{WIDGET_DESTROY_HOOK}> {} }")
1509
1510  INTERP.add_tk_procs('rb_out', 'ns args', <<-'EOL')
1511    if [regexp {^::} $ns] {
1512      set cmd {namespace eval $ns {ruby_cmd TkCore callback} $args}
1513    } else {
1514      set cmd {eval {ruby_cmd TkCore callback} $ns $args}
1515    }
1516    if {[set st [catch $cmd ret]] != 0} {
1517       #return -code $st $ret
1518       set idx [string first "\n\n" $ret]
1519       if {$idx > 0} {
1520          return -code $st \
1521                 -errorinfo [string range $ret [expr $idx + 2] \
1522                                               [string length $ret]] \
1523                 [string range $ret 0 [expr $idx - 1]]
1524       } else {
1525          return -code $st $ret
1526       }
1527    } else {
1528        return $ret
1529    }
1530  EOL
1531=begin
1532  INTERP.add_tk_procs('rb_out', 'args', <<-'EOL')
1533    if {[set st [catch {eval {ruby_cmd TkCore callback} $args} ret]] != 0} {
1534       #return -code $st $ret
1535       set idx [string first "\n\n" $ret]
1536       if {$idx > 0} {
1537          return -code $st \
1538                 -errorinfo [string range $ret [expr $idx + 2] \
1539                                               [string length $ret]] \
1540                 [string range $ret 0 [expr $idx - 1]]
1541       } else {
1542          return -code $st $ret
1543       }
1544    } else {
1545        return $ret
1546    }
1547  EOL
1548=end
1549=begin
1550  INTERP.add_tk_procs('rb_out', 'args', <<-'EOL')
1551    #regsub -all {\\} $args {\\\\} args
1552    #regsub -all {!} $args {\\!} args
1553    #regsub -all "{" $args "\\{" args
1554    regsub -all {(\\|!|\{|\})} $args {\\\1} args
1555    if {[set st [catch {ruby [format "TkCore.callback %%Q!%s!" $args]} ret]] != 0} {
1556       #return -code $st $ret
1557       set idx [string first "\n\n" $ret]
1558       if {$idx > 0} {
1559          return -code $st \
1560                 -errorinfo [string range $ret [expr $idx + 2] \
1561                                               [string length $ret]] \
1562                 [string range $ret 0 [expr $idx - 1]]
1563       } else {
1564          return -code $st $ret
1565       }
1566    } else {
1567        return $ret
1568    }
1569  EOL
1570=end
1571
1572  at_exit{ INTERP.remove_tk_procs(TclTkLib::FINALIZE_PROC_NAME) }
1573
1574  EventFlag = TclTkLib::EventFlag
1575
1576  def callback_break
1577    fail TkCallbackBreak, "Tk callback returns 'break' status"
1578  end
1579
1580  def callback_continue
1581    fail TkCallbackContinue, "Tk callback returns 'continue' status"
1582  end
1583
1584  def callback_return
1585    fail TkCallbackReturn, "Tk callback returns 'return' status"
1586  end
1587
1588  def TkCore.callback(*arg)
1589    begin
1590      if TkCore::INTERP.tk_cmd_tbl.kind_of?(Hash)
1591        #TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg)
1592        normal_ret = false
1593        ret = catch(:IRB_EXIT) do  # IRB hack
1594          retval = TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg)
1595          normal_ret = true
1596          retval
1597        end
1598        unless normal_ret
1599          # catch IRB_EXIT
1600          exit(ret)
1601        end
1602        ret
1603      end
1604    rescue SystemExit=>e
1605      exit(e.status)
1606    rescue Interrupt=>e
1607      fail(e)
1608    rescue Exception => e
1609      begin
1610        msg = _toUTF8(e.class.inspect) + ': ' +
1611              _toUTF8(e.message) + "\n" +
1612              "\n---< backtrace of Ruby side >-----\n" +
1613              _toUTF8(e.backtrace.join("\n")) +
1614              "\n---< backtrace of Tk side >-------"
1615        if TkCore::WITH_ENCODING
1616          msg.force_encoding('utf-8')
1617        else
1618          msg.instance_variable_set(:@encoding, 'utf-8')
1619        end
1620      rescue Exception
1621        msg = e.class.inspect + ': ' + e.message + "\n" +
1622              "\n---< backtrace of Ruby side >-----\n" +
1623              e.backtrace.join("\n") +
1624              "\n---< backtrace of Tk side >-------"
1625      end
1626      # TkCore::INTERP._set_global_var('errorInfo', msg)
1627      # fail(e)
1628      fail(e, msg)
1629    end
1630  end
1631=begin
1632  def TkCore.callback(arg_str)
1633    # arg = tk_split_list(arg_str)
1634    arg = tk_split_simplelist(arg_str)
1635    #_get_eval_string(TkUtil.eval_cmd(Tk_CMDTBL[arg.shift], *arg))
1636    #_get_eval_string(TkUtil.eval_cmd(TkCore::INTERP.tk_cmd_tbl[arg.shift],
1637    #                        *arg))
1638    # TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg)
1639    begin
1640      TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg)
1641    rescue Exception => e
1642      raise(e, e.class.inspect + ': ' + e.message + "\n" +
1643               "\n---< backtrace of Ruby side >-----\n" +
1644               e.backtrace.join("\n") +
1645               "\n---< backtrace of Tk side >-------")
1646    end
1647#=begin
1648#    cb_obj = TkCore::INTERP.tk_cmd_tbl[arg.shift]
1649#    unless $DEBUG
1650#      cb_obj.call(*arg)
1651#    else
1652#      begin
1653#       raise 'check backtrace'
1654#      rescue
1655#       # ignore backtrace before 'callback'
1656#       pos = -($!.backtrace.size)
1657#      end
1658#      begin
1659#       cb_obj.call(*arg)
1660#      rescue
1661#       trace = $!.backtrace
1662#       raise $!, "\n#{trace[0]}: #{$!.message} (#{$!.class})\n" +
1663#                 "\tfrom #{trace[1..pos].join("\n\tfrom ")}"
1664#      end
1665#    end
1666#=end
1667  end
1668=end
1669
1670  def load_cmd_on_ip(tk_cmd)
1671    bool(tk_call('auto_load', tk_cmd))
1672  end
1673
1674  def after(ms, cmd=Proc.new)
1675    cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret})
1676    after_id = tk_call_without_enc("after",ms,cmdid)
1677    after_id.instance_variable_set('@cmdid', cmdid)
1678    after_id
1679  end
1680=begin
1681  def after(ms, cmd=Proc.new)
1682    crit_bup = Thread.critical
1683    Thread.critical = true
1684
1685    myid = _curr_cmd_id
1686    cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(myid); ret})
1687
1688    Thread.critical = crit_bup
1689
1690    tk_call_without_enc("after",ms,cmdid)  # return id
1691#    return
1692#    if false #defined? Thread
1693#      Thread.start do
1694#       ms = Float(ms)/1000
1695#       ms = 10 if ms == 0
1696#       sleep ms/1000
1697#       cmd.call
1698#      end
1699#    else
1700#      cmdid = install_cmd(cmd)
1701#      tk_call("after",ms,cmdid)
1702#    end
1703  end
1704=end
1705
1706  def after_idle(cmd=Proc.new)
1707    cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret})
1708    after_id = tk_call_without_enc('after','idle',cmdid)
1709    after_id.instance_variable_set('@cmdid', cmdid)
1710    after_id
1711  end
1712=begin
1713  def after_idle(cmd=Proc.new)
1714    crit_bup = Thread.critical
1715    Thread.critical = true
1716
1717    myid = _curr_cmd_id
1718    cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(myid); ret})
1719
1720    Thread.critical = crit_bup
1721
1722    tk_call_without_enc('after','idle',cmdid)
1723  end
1724=end
1725
1726  def after_cancel(afterId)
1727    tk_call_without_enc('after','cancel',afterId)
1728    if (cmdid = afterId.instance_variable_get('@cmdid'))
1729      afterId.instance_variable_set('@cmdid', nil)
1730      uninstall_cmd(cmdid)
1731    end
1732    afterId
1733  end
1734
1735  def windowingsystem
1736    tk_call_without_enc('tk', 'windowingsystem')
1737  end
1738
1739  def scaling(scale=nil)
1740    if scale
1741      tk_call_without_enc('tk', 'scaling', scale)
1742    else
1743      Float(number(tk_call_without_enc('tk', 'scaling')))
1744    end
1745  end
1746  def scaling_displayof(win, scale=nil)
1747    if scale
1748      tk_call_without_enc('tk', 'scaling', '-displayof', win, scale)
1749    else
1750      Float(number(tk_call_without_enc('tk', '-displayof', win, 'scaling')))
1751    end
1752  end
1753
1754  def inactive
1755    Integer(tk_call_without_enc('tk', 'inactive'))
1756  end
1757  def inactive_displayof(win)
1758    Integer(tk_call_without_enc('tk', 'inactive', '-displayof', win))
1759  end
1760  def reset_inactive
1761    tk_call_without_enc('tk', 'inactive', 'reset')
1762  end
1763  def reset_inactive_displayof(win)
1764    tk_call_without_enc('tk', 'inactive', '-displayof', win, 'reset')
1765  end
1766
1767  def appname(name=None)
1768    tk_call('tk', 'appname', name)
1769  end
1770
1771  def appsend_deny
1772    tk_call('rename', 'send', '')
1773  end
1774
1775  def appsend(interp, async, *args)
1776    if $SAFE >= 4
1777      fail SecurityError, "cannot send Tk commands at level 4"
1778    elsif $SAFE >= 1 && args.find{|obj| obj.tainted?}
1779      fail SecurityError, "cannot send tainted Tk commands at level #{$SAFE}"
1780    end
1781    if async != true && async != false && async != nil
1782      args.unshift(async)
1783      async = false
1784    end
1785    if async
1786      tk_call('send', '-async', '--', interp, *args)
1787    else
1788      tk_call('send', '--', interp, *args)
1789    end
1790  end
1791
1792  def rb_appsend(interp, async, *args)
1793    if $SAFE >= 4
1794      fail SecurityError, "cannot send Ruby commands at level 4"
1795    elsif $SAFE >= 1 && args.find{|obj| obj.tainted?}
1796      fail SecurityError, "cannot send tainted Ruby commands at level #{$SAFE}"
1797    end
1798    if async != true && async != false && async != nil
1799      args.unshift(async)
1800      async = false
1801    end
1802    #args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"]/, '\\\\\&')}
1803    args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"\\]/, '\\\\\&')}
1804    # args.push(').to_s"')
1805    # appsend(interp, async, 'ruby "(', *args)
1806    args.push('}.call)"')
1807    appsend(interp, async, 'ruby "TkComm._get_eval_string(proc{', *args)
1808  end
1809
1810  def appsend_displayof(interp, win, async, *args)
1811    if $SAFE >= 4
1812      fail SecurityError, "cannot send Tk commands at level 4"
1813    elsif $SAFE >= 1 && args.find{|obj| obj.tainted?}
1814      fail SecurityError, "cannot send tainted Tk commands at level #{$SAFE}"
1815    end
1816    win = '.' if win == nil
1817    if async != true && async != false && async != nil
1818      args.unshift(async)
1819      async = false
1820    end
1821    if async
1822      tk_call('send', '-async', '-displayof', win, '--', interp, *args)
1823    else
1824      tk_call('send', '-displayor', win, '--', interp, *args)
1825    end
1826  end
1827
1828  def rb_appsend_displayof(interp, win, async, *args)
1829    if $SAFE >= 4
1830      fail SecurityError, "cannot send Ruby commands at level 4"
1831    elsif $SAFE >= 1 && args.find{|obj| obj.tainted?}
1832      fail SecurityError, "cannot send tainted Ruby commands at level #{$SAFE}"
1833    end
1834    win = '.' if win == nil
1835    if async != true && async != false && async != nil
1836      args.unshift(async)
1837      async = false
1838    end
1839    #args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"]/, '\\\\\&')}
1840    args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"\\]/, '\\\\\&')}
1841    # args.push(').to_s"')
1842    # appsend_displayof(interp, win, async, 'ruby "(', *args)
1843    args.push('}.call)"')
1844    appsend(interp, win, async, 'ruby "TkComm._get_eval_string(proc{', *args)
1845  end
1846
1847  def info(*args)
1848    tk_call('info', *args)
1849  end
1850
1851  def mainloop(check_root = true)
1852    if !TkCore::WITH_RUBY_VM
1853      TclTkLib.mainloop(check_root)
1854
1855    elsif TkCore::RUN_EVENTLOOP_ON_MAIN_THREAD
1856      # if TclTkLib::WINDOWING_SYSTEM == 'aqua' &&
1857      #if TkCore::INTERP._invoke_without_enc('tk','windowingsystem')=='aqua' &&
1858      #    Thread.current != Thread.main &&
1859      #    (TclTkLib.get_version <=> [8,4,TclTkLib::RELEASE_TYPE::FINAL,9]) > 0
1860      #  raise RuntimeError,
1861      #       "eventloop on TkAqua ( > Tk8.4.9 ) works on the main thread only"
1862      #end
1863      if Thread.current != Thread.main
1864        raise RuntimeError, "Tk.mainloop is allowed on the main thread only"
1865      end
1866      TclTkLib.mainloop(check_root)
1867
1868    else ### Ruby 1.9 !!!!!
1869      unless TkCore::INTERP.default_master?
1870        # [MultiTkIp] slave interp ?
1871        return TkCore::INTERP._thread_tkwait('window', '.') if check_root
1872      end
1873
1874      # like as 1.8, withdraw a root widget before calling Tk.mainloop
1875      TkCore::INTERP._eval_without_enc('catch {unset __initial_state_of_rubytk__}')
1876      INTERP_THREAD.run
1877
1878      begin
1879        TclTkLib.set_eventloop_window_mode(true)
1880
1881        # force run the eventloop
1882        TkCore::INTERP._eval_without_enc('update')
1883        TkCore::INTERP._eval_without_enc('catch {set __initial_state_of_rubytk__}')
1884        INTERP_THREAD.run
1885        if check_root
1886          INTERP_MUTEX.synchronize{
1887            INTERP_ROOT_CHECK.wait(INTERP_MUTEX)
1888            status = INTERP_THREAD_STATUS.value
1889            if status && TkCore::INTERP.default_master?
1890              INTERP_THREAD_STATUS.value = nil if $SAFE < 4
1891              raise status if status.kind_of?(Exception)
1892            end
1893          }
1894        else
1895          # INTERP_THREAD.value
1896          begin
1897            INTERP_THREAD.value
1898          rescue Exception => e
1899            raise e
1900          end
1901        end
1902      rescue Exception => e
1903        raise e
1904      ensure
1905        TclTkLib.set_eventloop_window_mode(false)
1906      end
1907    end
1908  end
1909
1910  def mainloop_thread?
1911    # true  : current thread is mainloop
1912    # nil   : there is no mainloop
1913    # false : mainloop is running on the other thread
1914    #         ( At then, it is dangerous to call Tk interpreter directly. )
1915    if !TkCore::WITH_RUBY_VM || TkCore::RUN_EVENTLOOP_ON_MAIN_THREAD
1916      ### Ruby 1.9 !!!!!!!!!!!
1917      TclTkLib.mainloop_thread?
1918    else
1919      Thread.current == INTERP_THREAD
1920    end
1921  end
1922
1923  def mainloop_exist?
1924    TclTkLib.mainloop_thread? != nil
1925  end
1926
1927  def is_mainloop?
1928    TclTkLib.mainloop_thread? == true
1929  end
1930
1931  def mainloop_watchdog(check_root = true)
1932    # watchdog restarts mainloop when mainloop is dead
1933    TclTkLib.mainloop_watchdog(check_root)
1934  end
1935
1936  def do_one_event(flag = TclTkLib::EventFlag::ALL)
1937    TclTkLib.do_one_event(flag)
1938  end
1939
1940  def set_eventloop_tick(timer_tick)
1941    TclTkLib.set_eventloop_tick(timer_tick)
1942  end
1943
1944  def get_eventloop_tick()
1945    TclTkLib.get_eventloop_tick
1946  end
1947
1948  def set_no_event_wait(wait)
1949    TclTkLib.set_no_even_wait(wait)
1950  end
1951
1952  def get_no_event_wait()
1953    TclTkLib.get_no_eventloop_wait
1954  end
1955
1956  def set_eventloop_weight(loop_max, no_event_tick)
1957    TclTkLib.set_eventloop_weight(loop_max, no_event_tick)
1958  end
1959
1960  def get_eventloop_weight()
1961    TclTkLib.get_eventloop_weight
1962  end
1963
1964  def restart(app_name = nil, keys = {})
1965    TkCore::INTERP.init_ip_internal
1966
1967    tk_call('set', 'argv0', app_name) if app_name
1968    if keys.kind_of?(Hash)
1969      # tk_call('set', 'argc', keys.size * 2)
1970      tk_call('set', 'argv', hash_kv(keys).join(' '))
1971    end
1972
1973    INTERP.restart
1974    nil
1975  end
1976
1977  def event_generate(win, context, keys=nil)
1978    #win = win.path if win.kind_of?(TkObject)
1979    if context.kind_of?(TkEvent::Event)
1980      context.generate(win, ((keys)? keys: {}))
1981    elsif keys
1982      tk_call_without_enc('event', 'generate', win,
1983                          "<#{tk_event_sequence(context)}>",
1984                          *hash_kv(keys, true))
1985    else
1986      tk_call_without_enc('event', 'generate', win,
1987                          "<#{tk_event_sequence(context)}>")
1988    end
1989    nil
1990  end
1991
1992  def messageBox(keys)
1993    tk_call('tk_messageBox', *hash_kv(keys))
1994  end
1995
1996  def getOpenFile(keys = nil)
1997    tk_call('tk_getOpenFile', *hash_kv(keys))
1998  end
1999  def getMultipleOpenFile(keys = nil)
2000    simplelist(tk_call('tk_getOpenFile', '-multiple', '1', *hash_kv(keys)))
2001  end
2002
2003  def getSaveFile(keys = nil)
2004    tk_call('tk_getSaveFile', *hash_kv(keys))
2005  end
2006  def getMultipleSaveFile(keys = nil)
2007    simplelist(tk_call('tk_getSaveFile', '-multiple', '1', *hash_kv(keys)))
2008  end
2009
2010  def chooseColor(keys = nil)
2011    tk_call('tk_chooseColor', *hash_kv(keys))
2012  end
2013
2014  def chooseDirectory(keys = nil)
2015    tk_call('tk_chooseDirectory', *hash_kv(keys))
2016  end
2017
2018  def _ip_eval_core(enc_mode, cmd_string)
2019    case enc_mode
2020    when nil
2021      res = INTERP._eval(cmd_string)
2022    when false
2023      res = INTERP._eval_without_enc(cmd_string)
2024    when true
2025      res = INTERP._eval_with_enc(cmd_string)
2026    end
2027    if  INTERP._return_value() != 0
2028      fail RuntimeError, res, error_at
2029    end
2030    return res
2031  end
2032  private :_ip_eval_core
2033
2034  def ip_eval(cmd_string)
2035    _ip_eval_core(nil, cmd_string)
2036  end
2037
2038  def ip_eval_without_enc(cmd_string)
2039    _ip_eval_core(false, cmd_string)
2040  end
2041
2042  def ip_eval_with_enc(cmd_string)
2043    _ip_eval_core(true, cmd_string)
2044  end
2045
2046  def _ip_invoke_core(enc_mode, *args)
2047    case enc_mode
2048    when false
2049      res = INTERP._invoke_without_enc(*args)
2050    when nil
2051      res = INTERP._invoke(*args)
2052    when true
2053      res = INTERP._invoke_with_enc(*args)
2054    end
2055    if  INTERP._return_value() != 0
2056      fail RuntimeError, res, error_at
2057    end
2058    return res
2059  end
2060  private :_ip_invoke_core
2061
2062  def ip_invoke(*args)
2063    _ip_invoke_core(nil, *args)
2064  end
2065
2066  def ip_invoke_without_enc(*args)
2067    _ip_invoke_core(false, *args)
2068  end
2069
2070  def ip_invoke_with_enc(*args)
2071    _ip_invoke_core(true, *args)
2072  end
2073
2074  def _tk_call_core(enc_mode, *args)
2075    ### puts args.inspect if $DEBUG
2076    #args.collect! {|x|ruby2tcl(x, enc_mode)}
2077    #args.compact!
2078    #args.flatten!
2079    args = _conv_args([], enc_mode, *args)
2080    puts 'invoke args => ' + args.inspect if $DEBUG
2081    ### print "=> ", args.join(" ").inspect, "\n" if $DEBUG
2082    begin
2083      # res = TkUtil.untrust(INTERP._invoke(*args))
2084      # res = INTERP._invoke(enc_mode, *args)
2085      res = _ip_invoke_core(enc_mode, *args)
2086      # >>>>>  _invoke returns a TAINTED string  <<<<<
2087    rescue NameError => err
2088      # err = $!
2089      begin
2090        args.unshift "unknown"
2091        #res = TkUtil.untrust(INTERP._invoke(*args))
2092        #res = INTERP._invoke(enc_mode, *args)
2093        res = _ip_invoke_core(enc_mode, *args)
2094        # >>>>>  _invoke returns a TAINTED string  <<<<<
2095      rescue StandardError => err2
2096        fail err2 unless /^invalid command/ =~ err2.message
2097        fail err
2098      end
2099    end
2100    if  INTERP._return_value() != 0
2101      fail RuntimeError, res, error_at
2102    end
2103    ### print "==> ", res.inspect, "\n" if $DEBUG
2104    return res
2105  end
2106  private :_tk_call_core
2107
2108  def tk_call(*args)
2109    _tk_call_core(nil, *args)
2110  end
2111
2112  def tk_call_without_enc(*args)
2113    _tk_call_core(false, *args)
2114  end
2115
2116  def tk_call_with_enc(*args)
2117    _tk_call_core(true, *args)
2118  end
2119
2120  def _tk_call_to_list_core(depth, arg_enc, val_enc, *args)
2121    args = _conv_args([], arg_enc, *args)
2122    val = _tk_call_core(false, *args)
2123    if !depth.kind_of?(Integer) || depth == 0
2124      tk_split_simplelist(val, false, val_enc)
2125    else
2126      tk_split_list(val, depth, false, val_enc)
2127    end
2128  end
2129  #private :_tk_call_to_list_core
2130
2131  def tk_call_to_list(*args)
2132    _tk_call_to_list_core(-1, nil, true, *args)
2133  end
2134
2135  def tk_call_to_list_without_enc(*args)
2136    _tk_call_to_list_core(-1, false, false, *args)
2137  end
2138
2139  def tk_call_to_list_with_enc(*args)
2140    _tk_call_to_list_core(-1, true, true, *args)
2141  end
2142
2143  def tk_call_to_simplelist(*args)
2144    _tk_call_to_list_core(0, nil, true, *args)
2145  end
2146
2147  def tk_call_to_simplelist_without_enc(*args)
2148    _tk_call_to_list_core(0, false, false, *args)
2149  end
2150
2151  def tk_call_to_simplelist_with_enc(*args)
2152    _tk_call_to_list_core(0, true, true, *args)
2153  end
2154end
2155
2156
2157module Tk
2158  include TkCore
2159  extend Tk
2160
2161  TCL_VERSION = INTERP._invoke_without_enc("info", "tclversion").freeze
2162  TCL_PATCHLEVEL = INTERP._invoke_without_enc("info", "patchlevel").freeze
2163
2164  major, minor = TCL_VERSION.split('.')
2165  TCL_MAJOR_VERSION = major.to_i
2166  TCL_MINOR_VERSION = minor.to_i
2167
2168  TK_VERSION  = INTERP._invoke_without_enc("set", "tk_version").freeze
2169  TK_PATCHLEVEL  = INTERP._invoke_without_enc("set", "tk_patchLevel").freeze
2170
2171  major, minor = TK_VERSION.split('.')
2172  TK_MAJOR_VERSION = major.to_i
2173  TK_MINOR_VERSION = minor.to_i
2174
2175  JAPANIZED_TK = (INTERP._invoke_without_enc("info", "commands",
2176                                             "kanji") != "").freeze
2177
2178  def Tk.const_missing(sym)
2179    case(sym)
2180    when :TCL_LIBRARY
2181      INTERP._invoke_without_enc('global', 'tcl_library')
2182      INTERP._invoke("set", "tcl_library").freeze
2183
2184    when :TK_LIBRARY
2185      INTERP._invoke_without_enc('global', 'tk_library')
2186      INTERP._invoke("set", "tk_library").freeze
2187
2188    when :LIBRARY
2189      INTERP._invoke("info", "library").freeze
2190
2191    #when :PKG_PATH, :PACKAGE_PATH, :TCL_PACKAGE_PATH
2192    #  INTERP._invoke_without_enc('global', 'tcl_pkgPath')
2193    #  tk_split_simplelist(INTERP._invoke('set', 'tcl_pkgPath'))
2194
2195    #when :LIB_PATH, :LIBRARY_PATH, :TCL_LIBRARY_PATH
2196    #  INTERP._invoke_without_enc('global', 'tcl_libPath')
2197    #  tk_split_simplelist(INTERP._invoke('set', 'tcl_libPath'))
2198
2199    when :PLATFORM, :TCL_PLATFORM
2200      if $SAFE >= 4
2201        fail SecurityError, "can't get #{sym} when $SAFE >= 4"
2202      end
2203      INTERP._invoke_without_enc('global', 'tcl_platform')
2204      Hash[*tk_split_simplelist(INTERP._invoke_without_enc('array', 'get',
2205                                                           'tcl_platform'))]
2206
2207    when :ENV
2208      INTERP._invoke_without_enc('global', 'env')
2209      Hash[*tk_split_simplelist(INTERP._invoke('array', 'get', 'env'))]
2210
2211    #when :AUTO_PATH   #<===
2212    #  tk_split_simplelist(INTERP._invoke('set', 'auto_path'))
2213
2214    #when :AUTO_OLDPATH
2215    #  tk_split_simplelist(INTERP._invoke('set', 'auto_oldpath'))
2216
2217    when :AUTO_INDEX
2218      INTERP._invoke_without_enc('global', 'auto_index')
2219      Hash[*tk_split_simplelist(INTERP._invoke('array', 'get', 'auto_index'))]
2220
2221    when :PRIV, :PRIVATE, :TK_PRIV
2222      priv = {}
2223      if INTERP._invoke_without_enc('info', 'vars', 'tk::Priv') != ""
2224        var_nam = 'tk::Priv'
2225      else
2226        var_nam = 'tkPriv'
2227      end
2228      INTERP._invoke_without_enc('global', var_nam)
2229      Hash[*tk_split_simplelist(INTERP._invoke('array', 'get',
2230                                               var_nam))].each{|k,v|
2231        k.freeze
2232        case v
2233        when /^-?\d+$/
2234          priv[k] = v.to_i
2235        when /^-?\d+\.?\d*(e[-+]?\d+)?$/
2236          priv[k] = v.to_f
2237        else
2238          priv[k] = v.freeze
2239        end
2240      }
2241      priv
2242
2243    else
2244      raise NameError, 'uninitialized constant Tk::' + sym.id2name
2245    end
2246  end
2247
2248  def Tk.errorInfo
2249    INTERP._invoke_without_enc('global', 'errorInfo')
2250    INTERP._invoke_without_enc('set', 'errorInfo')
2251  end
2252
2253  def Tk.errorCode
2254    INTERP._invoke_without_enc('global', 'errorCode')
2255    code = tk_split_simplelist(INTERP._invoke_without_enc('set', 'errorCode'))
2256    case code[0]
2257    when 'CHILDKILLED', 'CHILDSTATUS', 'CHILDSUSP'
2258      begin
2259        pid = Integer(code[1])
2260        code[1] = pid
2261      rescue
2262      end
2263    end
2264    code
2265  end
2266
2267  def Tk.has_mainwindow?
2268    INTERP.has_mainwindow?
2269  end
2270
2271  def root
2272    Tk::Root.new
2273  end
2274
2275  def Tk.load_tclscript(file, enc=nil)
2276    if enc
2277      # TCL_VERSION >= 8.5
2278      tk_call('source', '-encoding', enc, file)
2279    else
2280      tk_call('source', file)
2281    end
2282  end
2283
2284  def Tk.load_tcllibrary(file, pkg_name=None, interp=None)
2285    tk_call('load', file, pkg_name, interp)
2286  end
2287
2288  def Tk.unload_tcllibrary(*args)
2289    if args[-1].kind_of?(Hash)
2290      keys = _symbolkey2str(args.pop)
2291      nocomp = (keys['nocomplain'])? '-nocomplain': None
2292      keeplib = (keys['keeplibrary'])? '-keeplibrary': None
2293      tk_call('unload', nocomp, keeplib, '--', *args)
2294    else
2295      tk_call('unload', *args)
2296    end
2297  end
2298
2299  def Tk.pkgconfig_list(mod)
2300    # Tk8.5 feature
2301    if mod.kind_of?(Module)
2302      if mod.respond_to?(:package_name)
2303        pkgname = mod.package_name
2304      elsif mod.const_defined?(:PACKAGE_NAME)
2305        pkgname = mod::PACKAGE_NAME
2306      else
2307        fail NotImplementedError, 'may not be a module for a Tcl extension'
2308      end
2309    else
2310      pkgname = mod.to_s
2311    end
2312
2313    pkgname = '::' << pkgname unless pkgname =~ /^::/
2314
2315    tk_split_list(tk_call(pkgname + '::pkgconfig', 'list'))
2316  end
2317
2318  def Tk.pkgconfig_get(mod, key)
2319    # Tk8.5 feature
2320    if mod.kind_of?(Module)
2321      if mod.respond_to?(:package_name)
2322        pkgname = mod.package_name
2323      else
2324        fail NotImplementedError, 'may not be a module for a Tcl extension'
2325      end
2326    else
2327      pkgname = mod.to_s
2328    end
2329
2330    pkgname = '::' << pkgname unless pkgname =~ /^::/
2331
2332    tk_call(pkgname + '::pkgconfig', 'get', key)
2333  end
2334
2335  def Tk.tcl_pkgconfig_list
2336    # Tk8.5 feature
2337    Tk.pkgconfig_list('::tcl')
2338  end
2339
2340  def Tk.tcl_pkgconfig_get(key)
2341    # Tk8.5 feature
2342    Tk.pkgconfig_get('::tcl', key)
2343  end
2344
2345  def Tk.tk_pkgconfig_list
2346    # Tk8.5 feature
2347    Tk.pkgconfig_list('::tk')
2348  end
2349
2350  def Tk.tk_pkgconfig_get(key)
2351    # Tk8.5 feature
2352    Tk.pkgconfig_get('::tk', key)
2353  end
2354
2355  def Tk.bell(nice = false)
2356    if nice
2357      tk_call_without_enc('bell', '-nice')
2358    else
2359      tk_call_without_enc('bell')
2360    end
2361    nil
2362  end
2363
2364  def Tk.bell_on_display(win, nice = false)
2365    if nice
2366      tk_call_without_enc('bell', '-displayof', win, '-nice')
2367    else
2368      tk_call_without_enc('bell', '-displayof', win)
2369    end
2370    nil
2371  end
2372
2373  def Tk.destroy(*wins)
2374    #tk_call_without_enc('destroy', *wins)
2375    tk_call_without_enc('destroy', *(wins.collect{|win|
2376                                       if win.kind_of?(TkWindow)
2377                                         win.epath
2378                                       else
2379                                         win
2380                                       end
2381                                     }))
2382  end
2383
2384  def Tk.exit
2385    TkCore::INTERP.has_mainwindow? && tk_call_without_enc('destroy', '.')
2386  end
2387
2388  ################################################
2389
2390  def Tk.sleep(ms = nil, id = nil)
2391    if id
2392      var = (id.kind_of?(TkVariable))? id: TkVarAccess.new(id.to_s)
2393    else
2394      var = TkVariable.new
2395    end
2396
2397    var.value = tk_call_without_enc('after', ms, proc{ var.value = 0 }) if ms
2398    var.thread_wait
2399    ms
2400  end
2401
2402  def Tk.wakeup(id)
2403    ((id.kind_of?(TkVariable))? id: TkVarAccess.new(id.to_s)).value = 0
2404    nil
2405  end
2406
2407  ################################################
2408
2409  def Tk.pack(*args)
2410    TkPack.configure(*args)
2411  end
2412  def Tk.pack_forget(*args)
2413    TkPack.forget(*args)
2414  end
2415  def Tk.unpack(*args)
2416    TkPack.forget(*args)
2417  end
2418
2419  def Tk.grid(*args)
2420    TkGrid.configure(*args)
2421  end
2422  def Tk.grid_forget(*args)
2423    TkGrid.forget(*args)
2424  end
2425  def Tk.ungrid(*args)
2426    TkGrid.forget(*args)
2427  end
2428
2429  def Tk.place(*args)
2430    TkPlace.configure(*args)
2431  end
2432  def Tk.place_forget(*args)
2433    TkPlace.forget(*args)
2434  end
2435  def Tk.unplace(*args)
2436    TkPlace.forget(*args)
2437  end
2438
2439  def Tk.update(idle=nil)
2440    if idle
2441      tk_call_without_enc('update', 'idletasks')
2442    else
2443      tk_call_without_enc('update')
2444    end
2445  end
2446  def Tk.update_idletasks
2447    update(true)
2448  end
2449  def update(idle=nil)
2450    # only for backward compatibility (This never be recommended to use)
2451    Tk.update(idle)
2452    self
2453  end
2454
2455  # NOTE::
2456  #   If no eventloop-thread is running, "thread_update" method is same
2457  #   to "update" method. Else, "thread_update" method waits to complete
2458  #   idletask operation on the eventloop-thread.
2459  def Tk.thread_update(idle=nil)
2460    if idle
2461      tk_call_without_enc('thread_update', 'idletasks')
2462    else
2463      tk_call_without_enc('thread_update')
2464    end
2465  end
2466  def Tk.thread_update_idletasks
2467    thread_update(true)
2468  end
2469
2470  def Tk.lower_window(win, below=None)
2471    tk_call('lower', _epath(win), _epath(below))
2472    nil
2473  end
2474  def Tk.raise_window(win, above=None)
2475    tk_call('raise', _epath(win), _epath(above))
2476    nil
2477  end
2478
2479  def Tk.current_grabs(win = nil)
2480    if win
2481      window(tk_call_without_enc('grab', 'current', win))
2482    else
2483      tk_split_list(tk_call_without_enc('grab', 'current'))
2484    end
2485  end
2486
2487  def Tk.focus(display=nil)
2488    if display == nil
2489      window(tk_call_without_enc('focus'))
2490    else
2491      window(tk_call_without_enc('focus', '-displayof', display))
2492    end
2493  end
2494
2495  def Tk.focus_to(win, force=false)
2496    if force
2497      tk_call_without_enc('focus', '-force', win)
2498    else
2499      tk_call_without_enc('focus', win)
2500    end
2501  end
2502
2503  def Tk.focus_lastfor(win)
2504    window(tk_call_without_enc('focus', '-lastfor', win))
2505  end
2506
2507  def Tk.focus_next(win)
2508    TkManageFocus.next(win)
2509  end
2510
2511  def Tk.focus_prev(win)
2512    TkManageFocus.prev(win)
2513  end
2514
2515  def Tk.strictMotif(mode=None)
2516    bool(tk_call_without_enc('set', 'tk_strictMotif', mode))
2517  end
2518
2519  def Tk.show_kinsoku(mode='both')
2520    begin
2521      if /^8\.*/ === TK_VERSION  && JAPANIZED_TK
2522        tk_split_simplelist(tk_call('kinsoku', 'show', mode))
2523      end
2524    rescue
2525    end
2526  end
2527  def Tk.add_kinsoku(chars, mode='both')
2528    begin
2529      if /^8\.*/ === TK_VERSION  && JAPANIZED_TK
2530        tk_split_simplelist(tk_call('kinsoku', 'add', mode,
2531                                    *(chars.split(''))))
2532      else
2533        []
2534      end
2535    rescue
2536      []
2537    end
2538  end
2539  def Tk.delete_kinsoku(chars, mode='both')
2540    begin
2541      if /^8\.*/ === TK_VERSION  && JAPANIZED_TK
2542        tk_split_simplelist(tk_call('kinsoku', 'delete', mode,
2543                            *(chars.split(''))))
2544      end
2545    rescue
2546    end
2547  end
2548
2549  def Tk.toUTF8(str, encoding = nil)
2550    _toUTF8(str, encoding)
2551  end
2552
2553  def Tk.fromUTF8(str, encoding = nil)
2554    _fromUTF8(str, encoding)
2555  end
2556end
2557
2558###########################################
2559#  string with Tcl's encoding
2560###########################################
2561module Tk
2562  def Tk.subst_utf_backslash(str)
2563    Tk::EncodedString.subst_utf_backslash(str)
2564  end
2565  def Tk.subst_tk_backslash(str)
2566    Tk::EncodedString.subst_tk_backslash(str)
2567  end
2568  def Tk.utf_to_backslash_sequence(str)
2569    Tk::EncodedString.utf_to_backslash_sequence(str)
2570  end
2571  def Tk.utf_to_backslash(str)
2572    Tk::EncodedString.utf_to_backslash_sequence(str)
2573  end
2574  def Tk.to_backslash_sequence(str)
2575    Tk::EncodedString.to_backslash_sequence(str)
2576  end
2577end
2578
2579
2580###########################################
2581#  convert kanji string to/from utf-8
2582###########################################
2583if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK)
2584  module Tk
2585    module Encoding
2586      extend Encoding
2587
2588      TkCommandNames = ['encoding'.freeze].freeze
2589
2590      #############################################
2591
2592      if TkCore::WITH_ENCODING ### Ruby 1.9
2593        RubyEncoding = ::Encoding
2594
2595        # for saving GC cost
2596        #ENCNAMES_CMD = ['encoding'.freeze, 'names'.freeze]
2597        BINARY_NAME  = 'binary'.freeze
2598        UTF8_NAME    = 'utf-8'.freeze
2599        DEFAULT_EXTERNAL_NAME = RubyEncoding.default_external.name.freeze
2600        DEFAULT_INTERNAL_NAME = RubyEncoding.default_internal.name.freeze rescue nil
2601
2602        BINARY  = RubyEncoding.find(BINARY_NAME)
2603        UNKNOWN = RubyEncoding.find('ASCII-8BIT')
2604
2605        ### start of creating ENCODING_TABLE
2606        ENCODING_TABLE = TkCore::INTERP.encoding_table
2607=begin
2608        ENCODING_TABLE = {
2609          'binary'       => BINARY,
2610          # 'UNKNOWN-8BIT' => UNKNOWN,
2611        }
2612
2613        list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0],
2614                                                  ENCNAMES_CMD[1])
2615        TkCore::INTERP._split_tklist(list).each{|name|
2616          begin
2617            enc = RubyEncoding.find(name)
2618          rescue ArgumentError
2619            case name
2620            when 'identity'
2621              enc = BINARY
2622            when 'shiftjis'
2623              enc = RubyEncoding.find('Shift_JIS')
2624            when 'unicode'
2625              enc = RubyEncoding.find('UTF-8')
2626              #if Tk.tk_call('set', 'tcl_platform(byteOrder)') =='littleEndian'
2627              #  enc = RubyEncoding.find('UTF-16LE')
2628              #else
2629              #  enc = RubyEncoding.find('UTF-16BE')
2630              #end
2631            when 'symbol'
2632              # single byte data
2633              enc = RubyEncoding.find('ASCII-8BIT') ### ???
2634            else
2635              # unsupported on Ruby, but supported on Tk
2636              enc = TkCore::INTERP.create_dummy_encoding_for_tk(name)
2637            end
2638          end
2639          ENCODING_TABLE[name.freeze] = enc
2640        }
2641=end
2642=begin
2643        def ENCODING_TABLE.get_name(enc)
2644          orig_enc = enc
2645
2646          # unles enc, use system default
2647          #  1st: Ruby/Tk default encoding
2648          #  2nd: Tcl/Tk default encoding
2649          #  3rd: Ruby's default_external
2650          enc ||= TkCore::INTERP.encoding
2651          enc ||= TclTkLib.encoding_system
2652          enc ||= DEFAULT_EXTERNAL_NAME
2653
2654          if enc.kind_of?(RubyEncoding)
2655            # Ruby's Encoding object
2656            if (name = self.key(enc))
2657              return name
2658            end
2659
2660            # Is it new ?
2661            list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0],
2662                                                      ENCNAMES_CMD[1])
2663            TkComm.simplelist(list).each{|name|
2664              if ((enc == RubyEncoding.find(name)) rescue false)
2665                # new relation!! update table
2666                self[name.freeze] = enc
2667                return name
2668              end
2669            }
2670          else
2671            # String or Symbol ?
2672            if self[name = enc.to_s]
2673              return name
2674            end
2675
2676            # Is it new ?
2677            if (enc_obj = (RubyEncoding.find(name) rescue false))
2678              list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0],
2679                                                        ENCNAMES_CMD[1])
2680              if TkComm.simplelist(list).index(name)
2681                # Tk's encoding name ?
2682                self[name.freeze] = enc_obj  # new relation!! update table
2683                return name
2684              else
2685                # Ruby's encoding name ?
2686                if (name = self.key(enc_obj))
2687                  return name
2688                end
2689              end
2690            end
2691          end
2692
2693          fail ArgumentError, "unsupported Tk encoding '#{orig_enc}'"
2694        end
2695
2696        def ENCODING_TABLE.get_obj(enc)
2697          # returns the encoding object.
2698          # If 'enc' is the encoding name on Tk only, it returns nil.
2699          ((obj = self[self.get_name(enc)]).kind_of?(RubyEncoding))? obj: nil
2700        end
2701=end
2702        ### end of creating ENCODING_TABLE
2703
2704      end
2705
2706      #############################################
2707
2708      if TkCore::WITH_ENCODING
2709        ################################
2710        ### Ruby 1.9
2711        ################################
2712        def force_default_encoding(mode)
2713          TkCore::INTERP.force_default_encoding = mode
2714        end
2715
2716        def force_default_encoding?
2717          TkCore::INTERP.force_default_encoding?
2718        end
2719
2720        def default_encoding=(enc)
2721          TkCore::INTERP.default_encoding = Tk::Encoding::ENCODING_TABLE.get_name(enc)
2722        end
2723
2724        def encoding=(enc)
2725          TkCore::INTERP.encoding = Tk::Encoding::ENCODING_TABLE.get_name(enc)
2726        end
2727
2728        def encoding_name
2729          Tk::Encoding::ENCODING_TABLE.get_name(TkCore::INTERP.encoding)
2730        end
2731        def encoding_obj
2732          Tk::Encoding::ENCODING_TABLE.get_obj(TkCore::INTERP.encoding)
2733        end
2734        alias encoding encoding_name
2735        alias default_encoding encoding_name
2736
2737        def tk_encoding_names
2738          #TkComm.simplelist(TkCore::INTERP._invoke_without_enc(Tk::Encoding::ENCNAMES_CMD[0], Tk::Encoding::ENCNAMES_CMD[1]))
2739          TkComm.simplelist(TkCore::INTERP._invoke_without_enc('encoding', 'names'))
2740        end
2741        def encoding_names
2742          self.tk_encoding_names.find_all{|name|
2743            Tk::Encoding::ENCODING_TABLE.get_name(name) rescue false
2744          }
2745        end
2746        def encoding_objs
2747          self.tk_encoding_names.map!{|name|
2748            Tk::Encoding::ENCODING_TABLE.get_obj(name) rescue nil
2749          }.compact
2750        end
2751
2752        def encoding_system=(enc)
2753          TclTkLib.encoding_system = Tk::Encoding::ENCODING_TABLE.get_name(enc)
2754        end
2755
2756        def encoding_system_name
2757          Tk::Encoding::ENCODING_TABLE.get_name(TclTkLib.encoding_system)
2758        end
2759        def encoding_system_obj
2760          Tk::Encoding::ENCODING_TABLE.get_obj(TclTkLib.encoding_system)
2761        end
2762        alias encoding_system encoding_system_name
2763
2764        ################################
2765      else
2766        ################################
2767        ### Ruby 1.8-
2768        ################################
2769        def force_default_encoding=(mode)
2770          true
2771        end
2772
2773        def force_default_encoding?
2774          true
2775        end
2776
2777        def default_encoding=(enc)
2778          TkCore::INTERP.default_encoding = enc
2779        end
2780
2781        def encoding=(enc)
2782          TkCore::INTERP.encoding = enc
2783        end
2784
2785        def encoding_obj
2786          TkCore::INTERP.encoding
2787        end
2788        def encoding_name
2789          TkCore::INTERP.encoding
2790        end
2791        alias encoding encoding_name
2792        alias default_encoding encoding_name
2793
2794        def tk_encoding_names
2795          TkComm.simplelist(Tk.tk_call('encoding', 'names'))
2796        end
2797        def encoding_objs
2798          self.tk_encoding_names
2799        end
2800        def encoding_names
2801          self.tk_encoding_names
2802        end
2803
2804        def encoding_system=(enc)
2805          TclTkLib.encoding_system = enc
2806        end
2807
2808        def encoding_system_name
2809          TclTkLib.encoding_system
2810        end
2811        def encoding_system_obj
2812          TclTkLib.encoding_system
2813        end
2814        alias encoding_system encoding_system_name
2815
2816        ################################
2817      end
2818
2819      def encoding_convertfrom(str, enc=nil)
2820        enc = encoding_system_name unless enc
2821        str = str.dup
2822        if TkCore::WITH_ENCODING
2823          if str.kind_of?(Tk::EncodedString)
2824            str.__instance_variable_set('@encoding', nil)
2825          else
2826            str.instance_variable_set('@encoding', nil)
2827          end
2828          str.force_encoding('binary')
2829        else
2830          str.instance_variable_set('@encoding', 'binary')
2831        end
2832        ret = TkCore::INTERP._invoke_without_enc('encoding', 'convertfrom',
2833                                                 enc, str)
2834        if TkCore::WITH_ENCODING
2835          ret.force_encoding('utf-8')
2836        else
2837          Tk::UTF8_String.new(ret)
2838        end
2839        ret
2840      end
2841      alias encoding_convert_from encoding_convertfrom
2842
2843      def encoding_convertto(str, enc=nil)
2844        # str must be a UTF-8 string
2845        enc = encoding_system_name unless enc
2846        ret = TkCore::INTERP._invoke_without_enc('encoding', 'convertto',
2847                                                 enc, str)
2848        #ret.instance_variable_set('@encoding', 'binary')
2849        if TkCore::WITH_ENCODING
2850          #ret.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj('binary'))
2851          ret.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj(enc))
2852        end
2853        ret
2854      end
2855      alias encoding_convert_to encoding_convertto
2856
2857      def encoding_dirs
2858        # Tcl8.5 feature
2859        TkComm.simplelist(Tk.tk_call_without_enc('encoding', 'dirs'))
2860      end
2861
2862      def encoding_dirs=(dir_list) # an array or a Tcl's list string
2863        # Tcl8.5 feature
2864        Tk.tk_call_without_enc('encoding', 'dirs', dir_list)
2865      end
2866    end
2867
2868    extend Encoding
2869  end
2870
2871  class TclTkIp
2872    def force_default_encoding=(mode)
2873      @force_default_encoding[0] = (mode)? true: false
2874    end
2875
2876    def force_default_encoding?
2877      @force_default_encoding[0] ||= false
2878    end
2879
2880    def default_encoding=(name)
2881      name = name.name if Tk::WITH_ENCODING && name.kind_of?(::Encoding)
2882      @encoding[0] = name.to_s.dup
2883    end
2884
2885    # from tkencoding.rb by ttate@jaist.ac.jp
2886    #attr_accessor :encoding
2887    def encoding=(name)
2888      self.force_default_encoding = true  # for comaptibility
2889      self.default_encoding = name
2890    end
2891
2892    def encoding_name
2893      (@encoding[0])? @encoding[0].dup: nil
2894    end
2895    alias encoding encoding_name
2896    alias default_encoding encoding_name
2897
2898    def encoding_obj
2899      if Tk::WITH_ENCODING
2900        Tk::Encoding.tcl2rb_encoding(@encoding[0])
2901      else
2902        (@encoding[0])? @encoding[0].dup: nil
2903      end
2904    end
2905
2906    alias __toUTF8 _toUTF8
2907    alias __fromUTF8 _fromUTF8
2908
2909    if Object.const_defined?(:Encoding) && ::Encoding.class == Class
2910      # with Encoding (Ruby 1.9+)
2911      #
2912      # use functions on Tcl as default.
2913      # but when unsupported encoding on Tcl, use methods on Ruby.
2914      #
2915      def _toUTF8(str, enc = nil)
2916        if enc
2917          # use given encoding
2918          begin
2919            enc_name = Tk::Encoding::ENCODING_TABLE.get_name(enc)
2920          rescue
2921            # unknown encoding for Tk -> try to convert encoding on Ruby
2922            str = str.dup.force_encoding(enc)
2923            str.encode!(Tk::Encoding::UTF8_NAME) # modify self !!
2924            return str  # if no error, probably succeed converting
2925          end
2926        end
2927
2928        enc_name ||= str.instance_variable_get(:@encoding)
2929
2930        enc_name ||=
2931          Tk::Encoding::ENCODING_TABLE.get_name(str.encoding) rescue nil
2932
2933        if enc_name
2934          # str has its encoding information
2935          encstr = __toUTF8(str, enc_name)
2936          encstr.force_encoding(Tk::Encoding::UTF8_NAME)
2937          return encstr
2938        else
2939          # str.encoding isn't supported by Tk -> try to convert on Ruby
2940          begin
2941            return str.encode(Tk::Encoding::UTF8_NAME) # new string
2942          rescue
2943            # error -> ignore, try to use default encoding of Ruby/Tk
2944          end
2945        end
2946
2947        #enc_name ||=
2948        #  Tk::Encoding::ENCODING_TABLE.get_name(Tk.encoding) rescue nil
2949        enc_name ||= Tk::Encoding::ENCODING_TABLE.get_name(nil)
2950
2951        # is 'binary' encoding?
2952        if enc_name == Tk::Encoding::BINARY_NAME
2953          return str.dup.force_encoding(Tk::Encoding::BINARY_NAME)
2954        end
2955
2956        # force default encoding?
2957        if ! str.kind_of?(Tk::EncodedString) && self.force_default_encoding?
2958          enc_name = Tk::Encoding::ENCODING_TABLE.get_name(Tk.default_encoding)
2959        end
2960
2961        encstr = __toUTF8(str, enc_name)
2962        encstr.force_encoding(Tk::Encoding::UTF8_NAME)
2963        encstr
2964      end
2965      def _fromUTF8(str, enc = nil)
2966        # str must be UTF-8 or binary.
2967        enc_name = str.instance_variable_get(:@encoding)
2968        enc_name ||=
2969          Tk::Encoding::ENCODING_TABLE.get_name(str.encoding) rescue nil
2970
2971        # is 'binary' encoding?
2972        if enc_name == Tk::Encoding::BINARY_NAME
2973          return str.dup.force_encoding(Tk::Encoding::BINARY_NAME)
2974        end
2975
2976        # get target encoding name (if enc == nil, use default encoding)
2977        begin
2978          enc_name = Tk::Encoding::ENCODING_TABLE.get_name(enc)
2979        rescue
2980          # then, enc != nil
2981          # unknown encoding for Tk -> try to convert encoding on Ruby
2982          str = str.dup.force_encoding(Tk::Encoding::UTF8_NAME)
2983          str.encode!(enc) # modify self !!
2984          return str  # if no error, probably succeed converting
2985        end
2986
2987        encstr = __fromUTF8(str, enc_name)
2988        encstr.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj(enc_name))
2989        encstr
2990      end
2991      ###
2992    else
2993      # without Encoding (Ruby 1.8)
2994      def _toUTF8(str, encoding = nil)
2995        __toUTF8(str, encoding)
2996      end
2997      def _fromUTF8(str, encoding = nil)
2998        __fromUTF8(str, encoding)
2999      end
3000      ###
3001    end
3002
3003    alias __eval _eval
3004    alias __invoke _invoke
3005
3006    def _eval(cmd)
3007      _fromUTF8(__eval(_toUTF8(cmd)))
3008    end
3009
3010    def _invoke(*cmds)
3011      _fromUTF8(__invoke(*(cmds.collect{|cmd| _toUTF8(cmd)})))
3012    end
3013
3014    alias _eval_with_enc _eval
3015    alias _invoke_with_enc _invoke
3016
3017=begin
3018    #### --> definition is moved to TclTkIp module
3019
3020    def _toUTF8(str, encoding = nil)
3021      # decide encoding
3022      if encoding
3023        encoding = encoding.to_s
3024      elsif str.kind_of?(Tk::EncodedString) && str.encoding != nil
3025        encoding = str.encoding.to_s
3026      elsif str.instance_variable_get(:@encoding)
3027        encoding = str.instance_variable_get(:@encoding).to_s
3028      elsif defined?(@encoding) && @encoding != nil
3029        encoding = @encoding.to_s
3030      else
3031        encoding = __invoke('encoding', 'system')
3032      end
3033
3034      # convert
3035      case encoding
3036      when 'utf-8', 'binary'
3037        str
3038      else
3039        __toUTF8(str, encoding)
3040      end
3041    end
3042
3043    def _fromUTF8(str, encoding = nil)
3044      unless encoding
3045        if defined?(@encoding) && @encoding != nil
3046          encoding = @encoding.to_s
3047        else
3048          encoding = __invoke('encoding', 'system')
3049        end
3050      end
3051
3052      if str.kind_of?(Tk::EncodedString)
3053        if str.encoding == 'binary'
3054          str
3055        else
3056          __fromUTF8(str, encoding)
3057        end
3058      elsif str.instance_variable_get(:@encoding).to_s == 'binary'
3059        str
3060      else
3061        __fromUTF8(str, encoding)
3062      end
3063    end
3064=end
3065
3066=begin
3067    def _eval(cmd)
3068      if defined?(@encoding) && @encoding != 'utf-8'
3069        ret = if cmd.kind_of?(Tk::EncodedString)
3070                case cmd.encoding
3071                when 'utf-8', 'binary'
3072                  __eval(cmd)
3073                else
3074                  __eval(_toUTF8(cmd, cmd.encoding))
3075                end
3076              elsif cmd.instance_variable_get(:@encoding) == 'binary'
3077                __eval(cmd)
3078              else
3079                __eval(_toUTF8(cmd, @encoding))
3080              end
3081        if ret.kind_of?(String) && ret.instance_variable_get(:@encoding) == 'binary'
3082          ret
3083        else
3084          _fromUTF8(ret, @encoding)
3085        end
3086      else
3087        __eval(cmd)
3088      end
3089    end
3090
3091    def _invoke(*cmds)
3092      if defined?(@encoding) && @encoding != 'utf-8'
3093        cmds = cmds.collect{|cmd|
3094          if cmd.kind_of?(Tk::EncodedString)
3095            case cmd.encoding
3096            when 'utf-8', 'binary'
3097              cmd
3098            else
3099              _toUTF8(cmd, cmd.encoding)
3100            end
3101          elsif cmd.instance_variable_get(:@encoding) == 'binary'
3102            cmd
3103          else
3104            _toUTF8(cmd, @encoding)
3105          end
3106        }
3107        ret = __invoke(*cmds)
3108        if ret.kind_of?(String) && ret.instance_variable_get(:@encoding) == 'binary'
3109          ret
3110        else
3111          _fromUTF8(ret, @encoding)
3112        end
3113      else
3114        __invoke(*cmds)
3115        end
3116    end
3117=end
3118  end
3119
3120  module TclTkLib
3121    class << self
3122      def force_default_encoding=(mode)
3123        TkCore::INTERP.force_default_encoding = mode
3124      end
3125
3126      def force_default_encoding?
3127        TkCore::INTERP.force_default_encoding?
3128      end
3129
3130      def default_encoding=(name)
3131        TkCore::INTERP.default_encoding = name
3132      end
3133
3134      alias _encoding encoding
3135      alias _encoding= encoding=
3136      def encoding=(name)
3137        name = name.name if name.kind_of?(::Encoding) if Tk::WITH_ENCODING
3138        TkCore::INTERP.encoding = name
3139      end
3140
3141      def encoding_name
3142        TkCore::INTERP.encoding
3143      end
3144      alias encoding encoding_name
3145      alias default_encoding encoding_name
3146
3147      def encoding_obj
3148        if Tk::WITH_ENCODING
3149          Tk::Encoding.tcl2rb_encoding(TkCore::INTERP.encoding)
3150        else
3151          TkCore::INTERP.encoding
3152        end
3153      end
3154    end
3155  end
3156
3157  # estimate encoding
3158  unless TkCore::WITH_ENCODING
3159    case $KCODE
3160    when /^e/i  # EUC
3161      Tk.encoding = 'euc-jp'
3162      Tk.encoding_system = 'euc-jp'
3163    when /^s/i  # SJIS
3164      begin
3165        if Tk.encoding_system == 'cp932'
3166          Tk.encoding = 'cp932'
3167        else
3168          Tk.encoding = 'shiftjis'
3169          Tk.encoding_system = 'shiftjis'
3170        end
3171      rescue StandardError, NameError
3172        Tk.encoding = 'shiftjis'
3173        Tk.encoding_system = 'shiftjis'
3174      end
3175    when /^u/i  # UTF8
3176      Tk.encoding = 'utf-8'
3177      Tk.encoding_system = 'utf-8'
3178    else        # NONE
3179      if defined? DEFAULT_TK_ENCODING
3180        Tk.encoding_system = DEFAULT_TK_ENCODING
3181      end
3182      begin
3183        Tk.encoding = Tk.encoding_system
3184      rescue StandardError, NameError
3185        Tk.encoding = 'utf-8'
3186        Tk.encoding_system = 'utf-8'
3187      end
3188    end
3189
3190  else ### Ruby 1.9 !!!!!!!!!!!!
3191    # loc_enc_obj = (::Encoding.find(::Encoding.locale_charmap) rescue Tk::Encoding::UNKNOWN)
3192    loc_enc_obj = ::Encoding.find("locale")
3193    ext_enc_obj = ::Encoding.default_external
3194    int_enc_obj = ::Encoding.default_internal || ext_enc_obj
3195    tksys_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(Tk.encoding_system)
3196    # p [Tk.encoding, Tk.encoding_system, loc_enc_obj, ext_enc_obj]
3197
3198=begin
3199    if ext_enc_obj == Tk::Encoding::UNKNOWN
3200      if defined? DEFAULT_TK_ENCODING
3201        if DEFAULT_TK_ENCODING.kind_of?(::Encoding)
3202          tk_enc_name    = DEFAULT_TK_ENCODING.name
3203          tksys_enc_name = DEFAULT_TK_ENCODING.name
3204        else
3205          tk_enc_name    = DEFAULT_TK_ENCODING
3206          tksys_enc_name = DEFAULT_TK_ENCODING
3207        end
3208      else
3209        tk_enc_name    = loc_enc_obj.name
3210        tksys_enc_name = loc_enc_obj.name
3211      end
3212    else
3213      tk_enc_name    = ext_enc_obj.name
3214      tksys_enc_name = ext_enc_obj.name
3215    end
3216
3217    # Tk.encoding = tk_enc_name
3218    Tk.default_encoding = tk_enc_name
3219    Tk.encoding_system = tksys_enc_name
3220=end
3221
3222    if ext_enc_obj == Tk::Encoding::UNKNOWN
3223      if loc_enc_obj == Tk::Encoding::UNKNOWN
3224        # use Tk.encoding_system
3225      else
3226        # use locale_charmap
3227        begin
3228          loc_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(loc_enc_obj)
3229          if loc_enc_name && loc_enc_name != tksys_enc_name
3230            # use locale_charmap
3231            Tk.encoding_system = loc_enc_name
3232          else
3233            # use Tk.encoding_system
3234          end
3235        rescue ArgumentError
3236          # unsupported encoding on Tk -> use Tk.encoding_system
3237        end
3238      end
3239    else
3240      begin
3241        ext_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(ext_enc_obj)
3242        if ext_enc_name && ext_enc_name != tksys_enc_name
3243          # use default_external
3244          Tk.encoding_system = ext_enc_name
3245        else
3246          # use Tk.encoding_system
3247        end
3248      rescue ArgumentError
3249        # unsupported encoding on Tk -> use Tk.encoding_system
3250      end
3251    end
3252
3253    # setup Tk.encoding
3254    enc_name = nil
3255
3256    begin
3257      default_def = DEFAULT_TK_ENCODING
3258      if ::Encoding.find(default_def.to_s) != Tk::Encoding::UNKNOWN
3259        enc_name = Tk::Encoding::ENCODING_TABLE.get_name(default_def)
3260      end
3261    rescue NameError
3262      # ignore
3263      enc_name = nil
3264    rescue ArgumentError
3265      enc_name = nil
3266      fail ArgumentError,
3267           "DEFAULT_TK_ENCODING has an unknown encoding #{default_def}"
3268    end
3269
3270    unless enc_name
3271      #if ext_enc_obj == Tk::Encoding::UNKNOWN
3272      if int_enc_obj == Tk::Encoding::UNKNOWN
3273        if loc_enc_obj == Tk::Encoding::UNKNOWN
3274          # use Tk.encoding_system
3275          enc_name = tksys_enc_name
3276        else
3277          # use locale_charmap
3278          begin
3279            loc_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(loc_enc_obj)
3280            if loc_enc_name
3281              # use locale_charmap
3282              enc_name = loc_enc_name
3283            else
3284              # use Tk.encoding_system
3285              enc_name = tksys_enc_name
3286            end
3287          rescue ArgumentError
3288            # unsupported encoding on Tk -> use Tk.encoding_system
3289            enc_name = tksys_enc_name
3290          end
3291        end
3292      else
3293        begin
3294          #ext_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(ext_enc_obj)
3295          #if ext_enc_name && ext_enc_name != tksys_enc_name
3296          int_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(int_enc_obj)
3297          if int_enc_name
3298            # use default_internal
3299            enc_name = int_enc_name
3300          else
3301            # use Tk.encoding_system
3302            enc_name = tksys_enc_name
3303          end
3304        rescue ArgumentError
3305          # unsupported encoding on Tk -> use Tk.encoding_system
3306          enc_name = tksys_enc_name
3307        end
3308      end
3309    end
3310
3311    Tk.default_encoding = (enc_name)? enc_name: tksys_enc_name
3312  end
3313
3314else
3315  # dummy methods
3316  module Tk
3317    module Encoding
3318      extend Encoding
3319
3320      def force_default_encoding=(mode)
3321        nil
3322      end
3323
3324      def force_default_encoding?
3325        nil
3326      end
3327
3328      def default_encoding=(enc)
3329        nil
3330      end
3331      def default_encoding
3332        nil
3333      end
3334
3335      def encoding=(name)
3336        nil
3337      end
3338      def encoding
3339        nil
3340      end
3341      def encoding_names
3342        nil
3343      end
3344      def encoding_system
3345        nil
3346      end
3347      def encoding_system=(enc)
3348        nil
3349      end
3350
3351      def encoding_convertfrom(str, enc=None)
3352        str
3353      end
3354      alias encoding_convert_from encoding_convertfrom
3355
3356      def encoding_convertto(str, enc=None)
3357        str
3358      end
3359      alias encoding_convert_to encoding_convertto
3360      def encoding_dirs
3361        nil
3362      end
3363      def encoding_dirs=(dir_array)
3364        nil
3365      end
3366    end
3367
3368    extend Encoding
3369  end
3370
3371  class TclTkIp
3372    attr_accessor :encoding
3373
3374    alias __eval _eval
3375    alias __invoke _invoke
3376
3377    alias _eval_with_enc _eval
3378    alias _invoke_with_enc _invoke
3379  end
3380end
3381
3382
3383module TkBindCore
3384  #def bind(context, cmd=Proc.new, *args)
3385  #  Tk.bind(self, context, cmd, *args)
3386  #end
3387  def bind(context, *args)
3388    # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
3389    if TkComm._callback_entry?(args[0]) || !block_given?
3390      cmd = args.shift
3391    else
3392      cmd = Proc.new
3393    end
3394    Tk.bind(self, context, cmd, *args)
3395  end
3396
3397  #def bind_append(context, cmd=Proc.new, *args)
3398  #  Tk.bind_append(self, context, cmd, *args)
3399  #end
3400  def bind_append(context, *args)
3401    # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
3402    if TkComm._callback_entry?(args[0]) || !block_given?
3403      cmd = args.shift
3404    else
3405      cmd = Proc.new
3406    end
3407    Tk.bind_append(self, context, cmd, *args)
3408  end
3409
3410  def bind_remove(context)
3411    Tk.bind_remove(self, context)
3412  end
3413
3414  def bindinfo(context=nil)
3415    Tk.bindinfo(self, context)
3416  end
3417end
3418
3419
3420module TkTreatFont
3421  def __font_optkeys
3422    ['font']
3423  end
3424  private :__font_optkeys
3425
3426  def __pathname
3427    self.path
3428  end
3429  private :__pathname
3430
3431  ################################
3432
3433  def font_configinfo(key = nil)
3434    optkeys = __font_optkeys
3435    if key && !optkeys.find{|opt| opt.to_s == key.to_s}
3436      fail ArgumentError, "unknown font option name `#{key}'"
3437    end
3438
3439    win, tag = __pathname.split(':')
3440
3441    if key
3442      pathname = [win, tag, key].join(';')
3443      TkFont.used_on(pathname) ||
3444        TkFont.init_widget_font(pathname, *__confinfo_cmd)
3445    elsif optkeys.size == 1
3446      pathname = [win, tag, optkeys[0]].join(';')
3447      TkFont.used_on(pathname) ||
3448        TkFont.init_widget_font(pathname, *__confinfo_cmd)
3449    else
3450      fonts = {}
3451      optkeys.each{|k|
3452        k = k.to_s
3453        pathname = [win, tag, k].join(';')
3454        fonts[k] =
3455          TkFont.used_on(pathname) ||
3456          TkFont.init_widget_font(pathname, *__confinfo_cmd)
3457      }
3458      fonts
3459    end
3460  end
3461  alias fontobj font_configinfo
3462
3463  def font_configure(slot)
3464    pathname = __pathname
3465
3466    slot = _symbolkey2str(slot)
3467
3468    __font_optkeys.each{|optkey|
3469      optkey = optkey.to_s
3470      l_optkey = 'latin' << optkey
3471      a_optkey = 'ascii' << optkey
3472      k_optkey = 'kanji' << optkey
3473
3474      if slot.key?(optkey)
3475        fnt = slot.delete(optkey)
3476        if fnt.kind_of?(TkFont)
3477          slot.delete(l_optkey)
3478          slot.delete(a_optkey)
3479          slot.delete(k_optkey)
3480
3481          fnt.call_font_configure([pathname, optkey], *(__config_cmd << {}))
3482          next
3483        else
3484          if fnt
3485            if (slot.key?(l_optkey) ||
3486                slot.key?(a_optkey) ||
3487                slot.key?(k_optkey))
3488              fnt = TkFont.new(fnt)
3489
3490              lfnt = slot.delete(l_optkey)
3491              lfnt = slot.delete(a_optkey) if slot.key?(a_optkey)
3492              kfnt = slot.delete(k_optkey)
3493
3494              fnt.latin_replace(lfnt) if lfnt
3495              fnt.kanji_replace(kfnt) if kfnt
3496
3497              fnt.call_font_configure([pathname, optkey],
3498                                      *(__config_cmd << {}))
3499              next
3500            else
3501              fnt = hash_kv(fnt) if fnt.kind_of?(Hash)
3502              unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
3503                tk_call(*(__config_cmd << "-#{optkey}" << fnt))
3504              else
3505                begin
3506                  tk_call(*(__config_cmd << "-#{optkey}" << fnt))
3507                rescue
3508                  # ignore
3509                end
3510              end
3511            end
3512          end
3513          next
3514        end
3515      end
3516
3517      lfnt = slot.delete(l_optkey)
3518      lfnt = slot.delete(a_optkey) if slot.key?(a_optkey)
3519      kfnt = slot.delete(k_optkey)
3520
3521      if lfnt && kfnt
3522        TkFont.new(lfnt, kfnt).call_font_configure([pathname, optkey],
3523                                                   *(__config_cmd << {}))
3524      elsif lfnt
3525        latinfont_configure([lfnt, optkey])
3526      elsif kfnt
3527        kanjifont_configure([kfnt, optkey])
3528      end
3529    }
3530
3531    # configure other (without font) options
3532    tk_call(*(__config_cmd.concat(hash_kv(slot)))) if slot != {}
3533    self
3534  end
3535
3536  def latinfont_configure(ltn, keys=nil)
3537    if ltn.kind_of?(Array)
3538      key = ltn[1]
3539      ltn = ltn[0]
3540    else
3541      key = nil
3542    end
3543
3544    optkeys = __font_optkeys
3545    if key && !optkeys.find{|opt| opt.to_s == key.to_s}
3546      fail ArgumentError, "unknown font option name `#{key}'"
3547    end
3548
3549    win, tag = __pathname.split(':')
3550
3551    optkeys = [key] if key
3552
3553    optkeys.each{|optkey|
3554      optkey = optkey.to_s
3555
3556      pathname = [win, tag, optkey].join(';')
3557
3558      if (fobj = TkFont.used_on(pathname))
3559        fobj = TkFont.new(fobj) # create a new TkFont object
3560      elsif Tk::JAPANIZED_TK
3561        fobj = fontobj          # create a new TkFont object
3562      else
3563        ltn = hash_kv(ltn) if ltn.kind_of?(Hash)
3564        unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
3565          tk_call(*(__config_cmd << "-#{optkey}" << ltn))
3566        else
3567          begin
3568            tk_call(*(__config_cmd << "-#{optkey}" << ltn))
3569          rescue => e
3570            # ignore
3571          end
3572        end
3573        next
3574      end
3575
3576      if fobj.kind_of?(TkFont)
3577        if ltn.kind_of?(TkFont)
3578          conf = {}
3579          ltn.latin_configinfo.each{|k,val| conf[k] = val}
3580          if keys
3581            fobj.latin_configure(conf.update(keys))
3582          else
3583            fobj.latin_configure(conf)
3584          end
3585        else
3586          fobj.latin_replace(ltn)
3587        end
3588      end
3589
3590      fobj.call_font_configure([pathname, optkey], *(__config_cmd << {}))
3591    }
3592    self
3593  end
3594  alias asciifont_configure latinfont_configure
3595
3596  def kanjifont_configure(knj, keys=nil)
3597    if knj.kind_of?(Array)
3598      key = knj[1]
3599      knj = knj[0]
3600    else
3601      key = nil
3602    end
3603
3604    optkeys = __font_optkeys
3605    if key && !optkeys.find{|opt| opt.to_s == key.to_s}
3606      fail ArgumentError, "unknown font option name `#{key}'"
3607    end
3608
3609    win, tag = __pathname.split(':')
3610
3611    optkeys = [key] if key
3612
3613    optkeys.each{|optkey|
3614      optkey = optkey.to_s
3615
3616      pathname = [win, tag, optkey].join(';')
3617
3618      if (fobj = TkFont.used_on(pathname))
3619        fobj = TkFont.new(fobj) # create a new TkFont object
3620      elsif Tk::JAPANIZED_TK
3621        fobj = fontobj          # create a new TkFont object
3622      else
3623        knj = hash_kv(knj) if knj.kind_of?(Hash)
3624        unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
3625          tk_call(*(__config_cmd << "-#{optkey}" << knj))
3626        else
3627          begin
3628            tk_call(*(__config_cmd << "-#{optkey}" << knj))
3629          rescue => e
3630            # ignore
3631          end
3632        end
3633        next
3634      end
3635
3636      if fobj.kind_of?(TkFont)
3637        if knj.kind_of?(TkFont)
3638          conf = {}
3639          knj.kanji_configinfo.each{|k,val| conf[k] = val}
3640          if keys
3641            fobj.kanji_configure(conf.update(keys))
3642          else
3643            fobj.kanji_configure(conf)
3644          end
3645        else
3646          fobj.kanji_replace(knj)
3647        end
3648      end
3649
3650      fobj.call_font_configure([pathname, optkey], *(__config_cmd << {}))
3651    }
3652    self
3653  end
3654
3655  def font_copy(win, wintag=nil, winkey=nil, targetkey=nil)
3656    if wintag
3657      if winkey
3658        fnt = win.tagfontobj(wintag, winkey).dup
3659      else
3660        fnt = win.tagfontobj(wintag).dup
3661      end
3662    else
3663      if winkey
3664        fnt = win.fontobj(winkey).dup
3665      else
3666        fnt = win.fontobj.dup
3667      end
3668    end
3669
3670    if targetkey
3671      fnt.call_font_configure([__pathname, targetkey], *(__config_cmd << {}))
3672    else
3673      fnt.call_font_configure(__pathname, *(__config_cmd << {}))
3674    end
3675    self
3676  end
3677
3678  def latinfont_copy(win, wintag=nil, winkey=nil, targetkey=nil)
3679    if targetkey
3680      fontobj(targetkey).dup.call_font_configure([__pathname, targetkey],
3681                                                 *(__config_cmd << {}))
3682    else
3683      fontobj.dup.call_font_configure(__pathname, *(__config_cmd << {}))
3684    end
3685
3686    if wintag
3687      if winkey
3688        fontobj.latin_replace(win.tagfontobj(wintag, winkey).latin_font_id)
3689      else
3690        fontobj.latin_replace(win.tagfontobj(wintag).latin_font_id)
3691      end
3692    else
3693      if winkey
3694        fontobj.latin_replace(win.fontobj(winkey).latin_font_id)
3695      else
3696        fontobj.latin_replace(win.fontobj.latin_font_id)
3697      end
3698    end
3699    self
3700  end
3701  alias asciifont_copy latinfont_copy
3702
3703  def kanjifont_copy(win, wintag=nil, winkey=nil, targetkey=nil)
3704    if targetkey
3705      fontobj(targetkey).dup.call_font_configure([__pathname, targetkey],
3706                                                 *(__config_cmd << {}))
3707    else
3708        fontobj.dup.call_font_configure(__pathname, *(__config_cmd << {}))
3709    end
3710
3711    if wintag
3712      if winkey
3713        fontobj.kanji_replace(win.tagfontobj(wintag, winkey).kanji_font_id)
3714      else
3715        fontobj.kanji_replace(win.tagfontobj(wintag).kanji_font_id)
3716      end
3717    else
3718      if winkey
3719        fontobj.kanji_replace(win.fontobj(winkey).kanji_font_id)
3720      else
3721        fontobj.kanji_replace(win.fontobj.kanji_font_id)
3722      end
3723    end
3724    self
3725  end
3726end
3727
3728
3729module TkConfigMethod
3730  include TkUtil
3731  include TkTreatFont
3732
3733  def TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
3734    @mode || false
3735  end
3736  def TkConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode)
3737    fail SecurityError, "can't change the mode" if $SAFE>=4
3738    @mode = (mode)? true: false
3739  end
3740
3741  def __cget_cmd
3742    [self.path, 'cget']
3743  end
3744  private :__cget_cmd
3745
3746  def __config_cmd
3747    [self.path, 'configure']
3748  end
3749  private :__config_cmd
3750
3751  def __confinfo_cmd
3752    __config_cmd
3753  end
3754  private :__confinfo_cmd
3755
3756  def __configinfo_struct
3757    {:key=>0, :alias=>1, :db_name=>1, :db_class=>2,
3758      :default_value=>3, :current_value=>4}
3759  end
3760  private :__configinfo_struct
3761
3762  def __optkey_aliases
3763    {}
3764  end
3765  private :__optkey_aliases
3766
3767  def __numval_optkeys
3768    []
3769  end
3770  private :__numval_optkeys
3771
3772  def __numstrval_optkeys
3773    []
3774  end
3775  private :__numstrval_optkeys
3776
3777  def __boolval_optkeys
3778    ['exportselection', 'jump', 'setgrid', 'takefocus']
3779  end
3780  private :__boolval_optkeys
3781
3782  def __strval_optkeys
3783    [
3784      'text', 'label', 'show', 'data', 'file',
3785      'activebackground', 'activeforeground', 'background',
3786      'disabledforeground', 'disabledbackground', 'foreground',
3787      'highlightbackground', 'highlightcolor', 'insertbackground',
3788      'selectbackground', 'selectforeground', 'troughcolor'
3789    ]
3790  end
3791  private :__strval_optkeys
3792
3793  def __listval_optkeys
3794    []
3795  end
3796  private :__listval_optkeys
3797
3798  def __numlistval_optkeys
3799    []
3800  end
3801  private :__numlistval_optkeys
3802
3803  def __tkvariable_optkeys
3804    ['variable', 'textvariable']
3805  end
3806  private :__tkvariable_optkeys
3807
3808  def __val2ruby_optkeys  # { key=>proc, ... }
3809    # The method is used to convert a opt-value to a ruby's object.
3810    # When get the value of the option "key", "proc.call(value)" is called.
3811    {}
3812  end
3813  private :__val2ruby_optkeys
3814
3815  def __ruby2val_optkeys  # { key=>proc, ... }
3816    # The method is used to convert a ruby's object to a opt-value.
3817    # When set the value of the option "key", "proc.call(value)" is called.
3818    # That is, "-#{key} #{proc.call(value)}".
3819    {}
3820  end
3821  private :__ruby2val_optkeys
3822
3823  def __methodcall_optkeys  # { key=>method, ... }
3824    # The method is used to both of get and set.
3825    # Usually, the 'key' will not be a widget option.
3826    {}
3827  end
3828  private :__methodcall_optkeys
3829
3830  def __keyonly_optkeys  # { def_key=>undef_key or nil, ... }
3831    {}
3832  end
3833  private :__keyonly_optkeys
3834
3835  def __conv_keyonly_opts(keys)
3836    return keys unless keys.kind_of?(Hash)
3837    keyonly = __keyonly_optkeys
3838    keys2 = {}
3839    keys.each{|k, v|
3840      optkey = keyonly.find{|kk,vv| kk.to_s == k.to_s}
3841      if optkey
3842        defkey, undefkey = optkey
3843        if v
3844          keys2[defkey.to_s] = None
3845        elsif undefkey
3846          keys2[undefkey.to_s] = None
3847        else
3848          # remove key
3849        end
3850      else
3851        keys2[k.to_s] = v
3852      end
3853    }
3854    keys2
3855  end
3856  private :__conv_keyonly_opts
3857
3858  def config_hash_kv(keys, enc_mode = nil, conf = nil)
3859    hash_kv(__conv_keyonly_opts(keys), enc_mode, conf)
3860  end
3861
3862  ################################
3863
3864  def [](id)
3865    cget(id)
3866  end
3867
3868  def []=(id, val)
3869    configure(id, val)
3870    val
3871  end
3872
3873  def cget_tkstring(option)
3874    opt = option.to_s
3875    fail ArgumentError, "Invalid option `#{option.inspect}'" if opt.length == 0
3876    tk_call_without_enc(*(__cget_cmd << "-#{opt}"))
3877  end
3878
3879  def __cget_core(slot)
3880    orig_slot = slot
3881    slot = slot.to_s
3882
3883    if slot.length == 0
3884      fail ArgumentError, "Invalid option `#{orig_slot.inspect}'"
3885    end
3886
3887    alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot}
3888    if real_name
3889      slot = real_name.to_s
3890    end
3891
3892    if ( method = _symbolkey2str(__val2ruby_optkeys())[slot] )
3893      optval = tk_call_without_enc(*(__cget_cmd << "-#{slot}"))
3894      begin
3895        return method.call(optval)
3896      rescue => e
3897        warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG
3898        return optval
3899      end
3900    end
3901
3902    if ( method = _symbolkey2str(__methodcall_optkeys)[slot] )
3903      return self.__send__(method)
3904    end
3905
3906    case slot
3907    when /^(#{__numval_optkeys.join('|')})$/
3908      begin
3909        number(tk_call_without_enc(*(__cget_cmd << "-#{slot}")))
3910      rescue
3911        nil
3912      end
3913
3914    when /^(#{__numstrval_optkeys.join('|')})$/
3915      num_or_str(tk_call_without_enc(*(__cget_cmd << "-#{slot}")))
3916
3917    when /^(#{__boolval_optkeys.join('|')})$/
3918      begin
3919        bool(tk_call_without_enc(*(__cget_cmd << "-#{slot}")))
3920      rescue
3921        nil
3922      end
3923
3924    when /^(#{__listval_optkeys.join('|')})$/
3925      simplelist(tk_call_without_enc(*(__cget_cmd << "-#{slot}")))
3926
3927    when /^(#{__numlistval_optkeys.join('|')})$/
3928      conf = tk_call_without_enc(*(__cget_cmd << "-#{slot}"))
3929      if conf =~ /^[0-9+-]/
3930        list(conf)
3931      else
3932        conf
3933      end
3934
3935    when /^(#{__strval_optkeys.join('|')})$/
3936      _fromUTF8(tk_call_without_enc(*(__cget_cmd << "-#{slot}")))
3937
3938    when /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/
3939      fontcode = $1
3940      fontkey  = $2
3941      fnt = tk_tcl2ruby(tk_call_without_enc(*(__cget_cmd << "-#{fontkey}")), true)
3942      unless fnt.kind_of?(TkFont)
3943        fnt = fontobj(fontkey)
3944      end
3945      if fontcode == 'kanji' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/
3946        # obsolete; just for compatibility
3947        fnt.kanji_font
3948      else
3949        fnt
3950      end
3951
3952    when /^(#{__tkvariable_optkeys.join('|')})$/
3953      v = tk_call_without_enc(*(__cget_cmd << "-#{slot}"))
3954      (v.empty?)? nil: TkVarAccess.new(v)
3955
3956    else
3957      tk_tcl2ruby(tk_call_without_enc(*(__cget_cmd << "-#{slot}")), true)
3958    end
3959  end
3960  private :__cget_core
3961
3962  def cget(slot)
3963    unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
3964      __cget_core(slot)
3965    else
3966      begin
3967        __cget_core(slot)
3968      rescue => e
3969        if current_configinfo.has_key?(slot.to_s)
3970          # error on known option
3971          fail e
3972        else
3973          # unknown option
3974          nil
3975        end
3976      end
3977    end
3978  end
3979  def cget_strict(slot)
3980    # never use TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
3981    __cget_core(slot)
3982  end
3983
3984  def __configure_core(slot, value=None)
3985    if slot.kind_of? Hash
3986      slot = _symbolkey2str(slot)
3987
3988      __optkey_aliases.each{|alias_name, real_name|
3989        alias_name = alias_name.to_s
3990        if slot.has_key?(alias_name)
3991          slot[real_name.to_s] = slot.delete(alias_name)
3992        end
3993      }
3994
3995      __methodcall_optkeys.each{|key, method|
3996        value = slot.delete(key.to_s)
3997        self.__send__(method, value) if value
3998      }
3999
4000      __ruby2val_optkeys.each{|key, method|
4001        key = key.to_s
4002        slot[key] = method.call(slot[key]) if slot.has_key?(key)
4003      }
4004
4005      __keyonly_optkeys.each{|defkey, undefkey|
4006        conf = slot.find{|kk, vv| kk == defkey.to_s}
4007        if conf
4008          k, v = conf
4009          if v
4010            slot[k] = None
4011          else
4012            slot[undefkey.to_s] = None if undefkey
4013            slot.delete(k)
4014          end
4015        end
4016      }
4017
4018      if (slot.find{|k, v| k =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/})
4019        font_configure(slot)
4020      elsif slot.size > 0
4021        tk_call(*(__config_cmd.concat(hash_kv(slot))))
4022      end
4023
4024    else
4025      orig_slot = slot
4026      slot = slot.to_s
4027      if slot.length == 0
4028        fail ArgumentError, "Invalid option `#{orig_slot.inspect}'"
4029      end
4030
4031      alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot}
4032      if real_name
4033        slot = real_name.to_s
4034      end
4035
4036      if ( conf = __keyonly_optkeys.find{|k, v| k.to_s == slot} )
4037        defkey, undefkey = conf
4038        if value
4039          tk_call(*(__config_cmd << "-#{defkey}"))
4040        elsif undefkey
4041          tk_call(*(__config_cmd << "-#{undefkey}"))
4042        end
4043      elsif ( method = _symbolkey2str(__ruby2val_optkeys)[slot] )
4044        tk_call(*(__config_cmd << "-#{slot}" << method.call(value)))
4045      elsif ( method = _symbolkey2str(__methodcall_optkeys)[slot] )
4046        self.__send__(method, value)
4047      elsif (slot =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/)
4048        if value == None
4049          fontobj($2)
4050        else
4051          font_configure({slot=>value})
4052        end
4053      else
4054        tk_call(*(__config_cmd << "-#{slot}" << value))
4055      end
4056    end
4057    self
4058  end
4059  private :__configure_core
4060
4061  def __check_available_configure_options(keys)
4062    availables = self.current_configinfo.keys
4063
4064    # add non-standard keys
4065    availables |= __font_optkeys.map{|k|
4066      [k.to_s, "latin#{k}", "ascii#{k}", "kanji#{k}"]
4067    }.flatten
4068    availables |= __methodcall_optkeys.keys.map{|k| k.to_s}
4069    availables |= __keyonly_optkeys.keys.map{|k| k.to_s}
4070
4071    keys = _symbolkey2str(keys)
4072    keys.delete_if{|k, v| !(availables.include?(k))}
4073  end
4074
4075  def configure(slot, value=None)
4076    unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
4077      __configure_core(slot, value)
4078    else
4079      if slot.kind_of?(Hash)
4080        begin
4081          __configure_core(slot)
4082        rescue
4083          slot = __check_available_configure_options(slot)
4084          __configure_core(slot) unless slot.empty?
4085        end
4086      else
4087        begin
4088          __configure_core(slot, value)
4089        rescue => e
4090          if current_configinfo.has_key?(slot.to_s)
4091            # error on known option
4092            fail e
4093          else
4094            # unknown option
4095            nil
4096          end
4097        end
4098      end
4099    end
4100    self
4101  end
4102
4103  def configure_cmd(slot, value)
4104    configure(slot, install_cmd(value))
4105  end
4106
4107  def __configinfo_core(slot = nil)
4108    if TkComm::GET_CONFIGINFO_AS_ARRAY
4109      if (slot &&
4110          slot.to_s =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/)
4111        fontkey  = $2
4112        # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{fontkey}"))))
4113        conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{fontkey}")), false, true)
4114        conf[__configinfo_struct[:key]] =
4115          conf[__configinfo_struct[:key]][1..-1]
4116        if ( ! __configinfo_struct[:alias] \
4117            || conf.size > __configinfo_struct[:alias] + 1 )
4118          fnt = conf[__configinfo_struct[:default_value]]
4119          if TkFont.is_system_font?(fnt)
4120            conf[__configinfo_struct[:default_value]] = TkNamedFont.new(fnt)
4121          end
4122          conf[__configinfo_struct[:current_value]] = fontobj(fontkey)
4123        elsif ( __configinfo_struct[:alias] \
4124               && conf.size == __configinfo_struct[:alias] + 1 \
4125               && conf[__configinfo_struct[:alias]][0] == ?- )
4126          conf[__configinfo_struct[:alias]] =
4127            conf[__configinfo_struct[:alias]][1..-1]
4128        end
4129        conf
4130      else
4131        if slot
4132          slot = slot.to_s
4133
4134          alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot}
4135          if real_name
4136            slot = real_name.to_s
4137          end
4138
4139          case slot
4140          when /^(#{__val2ruby_optkeys().keys.join('|')})$/
4141            method = _symbolkey2str(__val2ruby_optkeys())[slot]
4142            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd() << "-#{slot}")), false, true)
4143            if ( __configinfo_struct[:default_value] \
4144                && conf[__configinfo_struct[:default_value]] )
4145              optval = conf[__configinfo_struct[:default_value]]
4146              begin
4147                val = method.call(optval)
4148              rescue => e
4149                warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG
4150                val = optval
4151              end
4152              conf[__configinfo_struct[:default_value]] = val
4153            end
4154            if ( conf[__configinfo_struct[:current_value]] )
4155              optval = conf[__configinfo_struct[:current_value]]
4156              begin
4157                val = method.call(optval)
4158              rescue => e
4159                warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG
4160                val = optval
4161              end
4162              conf[__configinfo_struct[:current_value]] = val
4163            end
4164
4165          when /^(#{__methodcall_optkeys.keys.join('|')})$/
4166            method = _symbolkey2str(__methodcall_optkeys)[slot]
4167            return [slot, '', '', '', self.__send__(method)]
4168
4169          when /^(#{__numval_optkeys.join('|')})$/
4170            # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}"))))
4171            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4172
4173            if ( __configinfo_struct[:default_value] \
4174                && conf[__configinfo_struct[:default_value]])
4175              begin
4176                conf[__configinfo_struct[:default_value]] =
4177                  number(conf[__configinfo_struct[:default_value]])
4178              rescue
4179                conf[__configinfo_struct[:default_value]] = nil
4180              end
4181            end
4182            if ( conf[__configinfo_struct[:current_value]] )
4183              begin
4184                conf[__configinfo_struct[:current_value]] =
4185                  number(conf[__configinfo_struct[:current_value]])
4186              rescue
4187                conf[__configinfo_struct[:current_value]] = nil
4188              end
4189            end
4190
4191          when /^(#{__numstrval_optkeys.join('|')})$/
4192            # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}"))))
4193            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4194
4195            if ( __configinfo_struct[:default_value] \
4196                && conf[__configinfo_struct[:default_value]])
4197              conf[__configinfo_struct[:default_value]] =
4198                num_or_str(conf[__configinfo_struct[:default_value]])
4199            end
4200            if ( conf[__configinfo_struct[:current_value]] )
4201              conf[__configinfo_struct[:current_value]] =
4202                num_or_str(conf[__configinfo_struct[:current_value]])
4203            end
4204
4205          when /^(#{__boolval_optkeys.join('|')})$/
4206            # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}"))))
4207            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4208
4209            if ( __configinfo_struct[:default_value] \
4210                && conf[__configinfo_struct[:default_value]])
4211              begin
4212                conf[__configinfo_struct[:default_value]] =
4213                  bool(conf[__configinfo_struct[:default_value]])
4214              rescue
4215                conf[__configinfo_struct[:default_value]] = nil
4216              end
4217            end
4218            if ( conf[__configinfo_struct[:current_value]] )
4219              begin
4220                conf[__configinfo_struct[:current_value]] =
4221                  bool(conf[__configinfo_struct[:current_value]])
4222              rescue
4223                conf[__configinfo_struct[:current_value]] = nil
4224              end
4225            end
4226
4227          when /^(#{__listval_optkeys.join('|')})$/
4228            # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}"))))
4229            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4230
4231            if ( __configinfo_struct[:default_value] \
4232                && conf[__configinfo_struct[:default_value]])
4233              conf[__configinfo_struct[:default_value]] =
4234                simplelist(conf[__configinfo_struct[:default_value]])
4235            end
4236            if ( conf[__configinfo_struct[:current_value]] )
4237              conf[__configinfo_struct[:current_value]] =
4238                simplelist(conf[__configinfo_struct[:current_value]])
4239            end
4240
4241          when /^(#{__numlistval_optkeys.join('|')})$/
4242            # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}"))))
4243            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4244
4245            if ( __configinfo_struct[:default_value] \
4246                && conf[__configinfo_struct[:default_value]] \
4247                && conf[__configinfo_struct[:default_value]] =~ /^[0-9]/ )
4248              conf[__configinfo_struct[:default_value]] =
4249                list(conf[__configinfo_struct[:default_value]])
4250            end
4251            if ( conf[__configinfo_struct[:current_value]] \
4252                && conf[__configinfo_struct[:current_value]] =~ /^[0-9]/ )
4253              conf[__configinfo_struct[:current_value]] =
4254                list(conf[__configinfo_struct[:current_value]])
4255            end
4256
4257          when /^(#{__strval_optkeys.join('|')})$/
4258            # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}"))))
4259            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4260
4261          when /^(#{__tkvariable_optkeys.join('|')})$/
4262            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4263
4264            if ( __configinfo_struct[:default_value] \
4265                && conf[__configinfo_struct[:default_value]])
4266              v = conf[__configinfo_struct[:default_value]]
4267              if v.empty?
4268                conf[__configinfo_struct[:default_value]] = nil
4269              else
4270                conf[__configinfo_struct[:default_value]] = TkVarAccess.new(v)
4271              end
4272            end
4273            if ( conf[__configinfo_struct[:current_value]] )
4274              v = conf[__configinfo_struct[:current_value]]
4275              if v.empty?
4276                conf[__configinfo_struct[:current_value]] = nil
4277              else
4278                conf[__configinfo_struct[:current_value]] = TkVarAccess.new(v)
4279              end
4280            end
4281
4282          else
4283            # conf = tk_split_list(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}"))))
4284            # conf = tk_split_list(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), 0, false, true)
4285            conf = tk_split_list(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), 1, false, true)
4286          end
4287          conf[__configinfo_struct[:key]] =
4288            conf[__configinfo_struct[:key]][1..-1]
4289
4290          if ( __configinfo_struct[:alias] \
4291              && conf.size == __configinfo_struct[:alias] + 1 \
4292              && conf[__configinfo_struct[:alias]][0] == ?- )
4293            conf[__configinfo_struct[:alias]] =
4294              conf[__configinfo_struct[:alias]][1..-1]
4295          end
4296
4297          conf
4298
4299        else
4300          # ret = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*__confinfo_cmd))).collect{|conflist|
4301          #  conf = tk_split_simplelist(conflist)
4302          ret = tk_split_simplelist(tk_call_without_enc(*__confinfo_cmd), false, false).collect{|conflist|
4303            conf = tk_split_simplelist(conflist, false, true)
4304            conf[__configinfo_struct[:key]] =
4305              conf[__configinfo_struct[:key]][1..-1]
4306
4307            optkey = conf[__configinfo_struct[:key]]
4308            case optkey
4309            when /^(#{__val2ruby_optkeys().keys.join('|')})$/
4310              method = _symbolkey2str(__val2ruby_optkeys())[optkey]
4311              if ( __configinfo_struct[:default_value] \
4312                  && conf[__configinfo_struct[:default_value]] )
4313                optval = conf[__configinfo_struct[:default_value]]
4314                begin
4315                  val = method.call(optval)
4316                rescue => e
4317                  warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG
4318                  val = optval
4319                end
4320                conf[__configinfo_struct[:default_value]] = val
4321              end
4322              if ( conf[__configinfo_struct[:current_value]] )
4323                optval = conf[__configinfo_struct[:current_value]]
4324                begin
4325                  val = method.call(optval)
4326                rescue => e
4327                  warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG
4328                  val = optval
4329                end
4330                conf[__configinfo_struct[:current_value]] = val
4331              end
4332
4333            when /^(#{__strval_optkeys.join('|')})$/
4334              # do nothing
4335
4336            when /^(#{__numval_optkeys.join('|')})$/
4337              if ( __configinfo_struct[:default_value] \
4338                  && conf[__configinfo_struct[:default_value]] )
4339                begin
4340                  conf[__configinfo_struct[:default_value]] =
4341                    number(conf[__configinfo_struct[:default_value]])
4342                rescue
4343                  conf[__configinfo_struct[:default_value]] = nil
4344                end
4345              end
4346              if ( conf[__configinfo_struct[:current_value]] )
4347                begin
4348                  conf[__configinfo_struct[:current_value]] =
4349                    number(conf[__configinfo_struct[:current_value]])
4350                rescue
4351                  conf[__configinfo_struct[:current_value]] = nil
4352                end
4353              end
4354
4355            when /^(#{__numstrval_optkeys.join('|')})$/
4356              if ( __configinfo_struct[:default_value] \
4357                  && conf[__configinfo_struct[:default_value]] )
4358                conf[__configinfo_struct[:default_value]] =
4359                  num_or_str(conf[__configinfo_struct[:default_value]])
4360              end
4361              if ( conf[__configinfo_struct[:current_value]] )
4362                conf[__configinfo_struct[:current_value]] =
4363                  num_or_str(conf[__configinfo_struct[:current_value]])
4364              end
4365
4366            when /^(#{__boolval_optkeys.join('|')})$/
4367              if ( __configinfo_struct[:default_value] \
4368                  && conf[__configinfo_struct[:default_value]] )
4369                begin
4370                  conf[__configinfo_struct[:default_value]] =
4371                    bool(conf[__configinfo_struct[:default_value]])
4372                rescue
4373                  conf[__configinfo_struct[:default_value]] = nil
4374                end
4375              end
4376              if ( conf[__configinfo_struct[:current_value]] )
4377                begin
4378                  conf[__configinfo_struct[:current_value]] =
4379                    bool(conf[__configinfo_struct[:current_value]])
4380                rescue
4381                  conf[__configinfo_struct[:current_value]] = nil
4382                end
4383              end
4384
4385            when /^(#{__listval_optkeys.join('|')})$/
4386              if ( __configinfo_struct[:default_value] \
4387                  && conf[__configinfo_struct[:default_value]] )
4388                conf[__configinfo_struct[:default_value]] =
4389                  simplelist(conf[__configinfo_struct[:default_value]])
4390              end
4391              if ( conf[__configinfo_struct[:current_value]] )
4392                conf[__configinfo_struct[:current_value]] =
4393                  simplelist(conf[__configinfo_struct[:current_value]])
4394              end
4395
4396            when /^(#{__numlistval_optkeys.join('|')})$/
4397              if ( __configinfo_struct[:default_value] \
4398                  && conf[__configinfo_struct[:default_value]] \
4399                  && conf[__configinfo_struct[:default_value]] =~ /^[0-9]/ )
4400                conf[__configinfo_struct[:default_value]] =
4401                  list(conf[__configinfo_struct[:default_value]])
4402              end
4403              if ( conf[__configinfo_struct[:current_value]] \
4404                  && conf[__configinfo_struct[:current_value]] =~ /^[0-9]/ )
4405                conf[__configinfo_struct[:current_value]] =
4406                  list(conf[__configinfo_struct[:current_value]])
4407              end
4408
4409            when /^(#{__tkvariable_optkeys.join('|')})$/
4410              if ( __configinfo_struct[:default_value] \
4411                  && conf[__configinfo_struct[:default_value]] )
4412                v = conf[__configinfo_struct[:default_value]]
4413                if v.empty?
4414                  conf[__configinfo_struct[:default_value]] = nil
4415                else
4416                  conf[__configinfo_struct[:default_value]] = TkVarAccess.new(v)
4417                end
4418              end
4419              if ( conf[__configinfo_struct[:current_value]] )
4420                v = conf[__configinfo_struct[:current_value]]
4421                if v.empty?
4422                  conf[__configinfo_struct[:current_value]] = nil
4423                else
4424                  conf[__configinfo_struct[:current_value]] = TkVarAccess.new(v)
4425                end
4426              end
4427
4428            else
4429              if ( __configinfo_struct[:default_value] \
4430                  && conf[__configinfo_struct[:default_value]] )
4431                if conf[__configinfo_struct[:default_value]].index('{')
4432                  conf[__configinfo_struct[:default_value]] =
4433                    tk_split_list(conf[__configinfo_struct[:default_value]])
4434                else
4435                  conf[__configinfo_struct[:default_value]] =
4436                    tk_tcl2ruby(conf[__configinfo_struct[:default_value]])
4437                end
4438              end
4439              if conf[__configinfo_struct[:current_value]]
4440                if conf[__configinfo_struct[:current_value]].index('{')
4441                  conf[__configinfo_struct[:current_value]] =
4442                    tk_split_list(conf[__configinfo_struct[:current_value]])
4443                else
4444                  conf[__configinfo_struct[:current_value]] =
4445                    tk_tcl2ruby(conf[__configinfo_struct[:current_value]])
4446                end
4447              end
4448            end
4449
4450            if ( __configinfo_struct[:alias] \
4451                && conf.size == __configinfo_struct[:alias] + 1 \
4452                && conf[__configinfo_struct[:alias]][0] == ?- )
4453              conf[__configinfo_struct[:alias]] =
4454                conf[__configinfo_struct[:alias]][1..-1]
4455            end
4456
4457            conf
4458          }
4459
4460          __font_optkeys.each{|optkey|
4461            optkey = optkey.to_s
4462            fontconf = ret.assoc(optkey)
4463            if fontconf && fontconf.size > 2
4464              ret.delete_if{|inf| inf[0] =~ /^(|latin|ascii|kanji)#{optkey}$/}
4465              fnt = fontconf[__configinfo_struct[:default_value]]
4466              if TkFont.is_system_font?(fnt)
4467                fontconf[__configinfo_struct[:default_value]] \
4468                  = TkNamedFont.new(fnt)
4469              end
4470              fontconf[__configinfo_struct[:current_value]] = fontobj(optkey)
4471              ret.push(fontconf)
4472            end
4473          }
4474
4475          __methodcall_optkeys.each{|optkey, m|
4476            ret << [optkey.to_s, '', '', '', self.__send__(m)]
4477          }
4478
4479          ret
4480        end
4481      end
4482
4483    else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
4484      if (slot &&
4485          slot.to_s =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/)
4486        fontkey  = $2
4487        # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{fontkey}"))))
4488        conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{fontkey}")), false, true)
4489        conf[__configinfo_struct[:key]] =
4490          conf[__configinfo_struct[:key]][1..-1]
4491
4492        if ( ! __configinfo_struct[:alias] \
4493            || conf.size > __configinfo_struct[:alias] + 1 )
4494          fnt = conf[__configinfo_struct[:default_value]]
4495          if TkFont.is_system_font?(fnt)
4496            conf[__configinfo_struct[:default_value]] = TkNamedFont.new(fnt)
4497          end
4498          conf[__configinfo_struct[:current_value]] = fontobj(fontkey)
4499          { conf.shift => conf }
4500        elsif ( __configinfo_struct[:alias] \
4501               && conf.size == __configinfo_struct[:alias] + 1 )
4502          if conf[__configinfo_struct[:alias]][0] == ?-
4503            conf[__configinfo_struct[:alias]] =
4504              conf[__configinfo_struct[:alias]][1..-1]
4505          end
4506          { conf[0] => conf[1] }
4507        else
4508          { conf.shift => conf }
4509        end
4510      else
4511        if slot
4512          slot = slot.to_s
4513
4514          alias_name, real_name = __optkey_aliases.find{|k,var| k.to_s == slot}
4515          if real_name
4516            slot = real_name.to_s
4517          end
4518
4519          case slot
4520          when /^(#{__val2ruby_optkeys().keys.join('|')})$/
4521            method = _symbolkey2str(__val2ruby_optkeys())[slot]
4522            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4523            if ( __configinfo_struct[:default_value] \
4524                && conf[__configinfo_struct[:default_value]] )
4525              optval = conf[__configinfo_struct[:default_value]]
4526              begin
4527                val = method.call(optval)
4528              rescue => e
4529                warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG
4530                val = optval
4531              end
4532              conf[__configinfo_struct[:default_value]] = val
4533            end
4534            if ( conf[__configinfo_struct[:current_value]] )
4535              optval = conf[__configinfo_struct[:current_value]]
4536              begin
4537                val = method.call(optval)
4538              rescue => e
4539                warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG
4540                val = optval
4541              end
4542              conf[__configinfo_struct[:current_value]] = val
4543            end
4544
4545          when /^(#{__methodcall_optkeys.keys.join('|')})$/
4546            method = _symbolkey2str(__methodcall_optkeys)[slot]
4547            return {slot => ['', '', '', self.__send__(method)]}
4548
4549          when /^(#{__numval_optkeys.join('|')})$/
4550            # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}"))))
4551            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4552
4553            if ( __configinfo_struct[:default_value] \
4554                && conf[__configinfo_struct[:default_value]] )
4555              begin
4556                conf[__configinfo_struct[:default_value]] =
4557                  number(conf[__configinfo_struct[:default_value]])
4558              rescue
4559                conf[__configinfo_struct[:default_value]] = nil
4560              end
4561            end
4562            if ( conf[__configinfo_struct[:current_value]] )
4563              begin
4564                conf[__configinfo_struct[:current_value]] =
4565                  number(conf[__configinfo_struct[:current_value]])
4566              rescue
4567                conf[__configinfo_struct[:current_value]] = nil
4568              end
4569            end
4570
4571          when /^(#{__numstrval_optkeys.join('|')})$/
4572            # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}"))))
4573            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4574
4575            if ( __configinfo_struct[:default_value] \
4576                && conf[__configinfo_struct[:default_value]] )
4577              conf[__configinfo_struct[:default_value]] =
4578                num_or_str(conf[__configinfo_struct[:default_value]])
4579            end
4580            if ( conf[__configinfo_struct[:current_value]] )
4581              conf[__configinfo_struct[:current_value]] =
4582                num_or_str(conf[__configinfo_struct[:current_value]])
4583            end
4584
4585          when /^(#{__boolval_optkeys.join('|')})$/
4586            # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}"))))
4587            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4588
4589            if ( __configinfo_struct[:default_value] \
4590                && conf[__configinfo_struct[:default_value]] )
4591              begin
4592                conf[__configinfo_struct[:default_value]] =
4593                  bool(conf[__configinfo_struct[:default_value]])
4594              rescue
4595                conf[__configinfo_struct[:default_value]] = nil
4596              end
4597            end
4598            if ( conf[__configinfo_struct[:current_value]] )
4599              begin
4600                conf[__configinfo_struct[:current_value]] =
4601                  bool(conf[__configinfo_struct[:current_value]])
4602              rescue
4603                conf[__configinfo_struct[:current_value]] = nil
4604              end
4605            end
4606
4607          when /^(#{__listval_optkeys.join('|')})$/
4608            # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}"))))
4609            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4610
4611            if ( __configinfo_struct[:default_value] \
4612                && conf[__configinfo_struct[:default_value]] )
4613              conf[__configinfo_struct[:default_value]] =
4614                simplelist(conf[__configinfo_struct[:default_value]])
4615            end
4616            if ( conf[__configinfo_struct[:current_value]] )
4617              conf[__configinfo_struct[:current_value]] =
4618                simplelist(conf[__configinfo_struct[:current_value]])
4619            end
4620
4621          when /^(#{__numlistval_optkeys.join('|')})$/
4622            # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}"))))
4623            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4624
4625            if ( __configinfo_struct[:default_value] \
4626                && conf[__configinfo_struct[:default_value]] \
4627                && conf[__configinfo_struct[:default_value]] =~ /^[0-9]/ )
4628              conf[__configinfo_struct[:default_value]] =
4629                list(conf[__configinfo_struct[:default_value]])
4630            end
4631            if ( conf[__configinfo_struct[:current_value]] \
4632                && conf[__configinfo_struct[:current_value]] =~ /^[0-9]/ )
4633              conf[__configinfo_struct[:current_value]] =
4634                list(conf[__configinfo_struct[:current_value]])
4635            end
4636
4637          when /^(#{__tkvariable_optkeys.join('|')})$/
4638            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4639
4640            if ( __configinfo_struct[:default_value] \
4641                && conf[__configinfo_struct[:default_value]] )
4642              v = conf[__configinfo_struct[:default_value]]
4643              if v.empty?
4644                conf[__configinfo_struct[:default_value]] = nil
4645              else
4646                conf[__configinfo_struct[:default_value]] = TkVarAccess.new(v)
4647              end
4648            end
4649            if ( conf[__configinfo_struct[:current_value]] )
4650              v = conf[__configinfo_struct[:current_value]]
4651              if v.empty?
4652                conf[__configinfo_struct[:current_value]] = nil
4653              else
4654                conf[__configinfo_struct[:current_value]] = TkVarAccess.new(v)
4655              end
4656            end
4657
4658          when /^(#{__strval_optkeys.join('|')})$/
4659            # conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}"))))
4660            conf = tk_split_simplelist(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), false, true)
4661          else
4662            # conf = tk_split_list(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}"))))
4663            conf = tk_split_list(tk_call_without_enc(*(__confinfo_cmd << "-#{slot}")), 0, false, true)
4664          end
4665          conf[__configinfo_struct[:key]] =
4666            conf[__configinfo_struct[:key]][1..-1]
4667
4668          if ( __configinfo_struct[:alias] \
4669              && conf.size == __configinfo_struct[:alias] + 1 )
4670            if conf[__configinfo_struct[:alias]][0] == ?-
4671              conf[__configinfo_struct[:alias]] =
4672                conf[__configinfo_struct[:alias]][1..-1]
4673            end
4674            { conf[0] => conf[1] }
4675          else
4676            { conf.shift => conf }
4677          end
4678
4679        else
4680          ret = {}
4681          # tk_split_simplelist(_fromUTF8(tk_call_without_enc(*__confinfo_cmd))).each{|conflist|
4682          #  conf = tk_split_simplelist(conflist)
4683          tk_split_simplelist(tk_call_without_enc(*__confinfo_cmd), false, false).each{|conflist|
4684            conf = tk_split_simplelist(conflist, false, true)
4685            conf[__configinfo_struct[:key]] =
4686              conf[__configinfo_struct[:key]][1..-1]
4687
4688            optkey = conf[__configinfo_struct[:key]]
4689            case optkey
4690            when /^(#{__val2ruby_optkeys().keys.join('|')})$/
4691              method = _symbolkey2str(__val2ruby_optkeys())[optkey]
4692              if ( __configinfo_struct[:default_value] \
4693                  && conf[__configinfo_struct[:default_value]] )
4694                optval = conf[__configinfo_struct[:default_value]]
4695                begin
4696                  val = method.call(optval)
4697                rescue => e
4698                  warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG
4699                  val = optval
4700                end
4701                conf[__configinfo_struct[:default_value]] = val
4702              end
4703              if ( conf[__configinfo_struct[:current_value]] )
4704                optval = conf[__configinfo_struct[:current_value]]
4705                begin
4706                  val = method.call(optval)
4707                rescue => e
4708                  warn("Warning:: #{e.message} (when #{method}.call(#{optval.inspect})") if $DEBUG
4709                  val = optval
4710                end
4711                conf[__configinfo_struct[:current_value]] = val
4712              end
4713
4714            when /^(#{__strval_optkeys.join('|')})$/
4715              # do nothing
4716
4717            when /^(#{__numval_optkeys.join('|')})$/
4718              if ( __configinfo_struct[:default_value] \
4719                  && conf[__configinfo_struct[:default_value]] )
4720                begin
4721                  conf[__configinfo_struct[:default_value]] =
4722                    number(conf[__configinfo_struct[:default_value]])
4723                rescue
4724                  conf[__configinfo_struct[:default_value]] = nil
4725                end
4726              end
4727              if ( conf[__configinfo_struct[:current_value]] )
4728                begin
4729                  conf[__configinfo_struct[:current_value]] =
4730                    number(conf[__configinfo_struct[:current_value]])
4731                rescue
4732                  conf[__configinfo_struct[:current_value]] = nil
4733                end
4734              end
4735
4736            when /^(#{__numstrval_optkeys.join('|')})$/
4737              if ( __configinfo_struct[:default_value] \
4738                  && conf[__configinfo_struct[:default_value]] )
4739                conf[__configinfo_struct[:default_value]] =
4740                  num_or_str(conf[__configinfo_struct[:default_value]])
4741              end
4742              if ( conf[__configinfo_struct[:current_value]] )
4743                conf[__configinfo_struct[:current_value]] =
4744                  num_or_str(conf[__configinfo_struct[:current_value]])
4745              end
4746
4747            when /^(#{__boolval_optkeys.join('|')})$/
4748              if ( __configinfo_struct[:default_value] \
4749                  && conf[__configinfo_struct[:default_value]] )
4750                begin
4751                  conf[__configinfo_struct[:default_value]] =
4752                    bool(conf[__configinfo_struct[:default_value]])
4753                rescue
4754                  conf[__configinfo_struct[:default_value]] = nil
4755                end
4756              end
4757              if ( conf[__configinfo_struct[:current_value]] )
4758                begin
4759                  conf[__configinfo_struct[:current_value]] =
4760                    bool(conf[__configinfo_struct[:current_value]])
4761                rescue
4762                  conf[__configinfo_struct[:current_value]] = nil
4763                end
4764              end
4765
4766            when /^(#{__listval_optkeys.join('|')})$/
4767              if ( __configinfo_struct[:default_value] \
4768                  && conf[__configinfo_struct[:default_value]] )
4769                conf[__configinfo_struct[:default_value]] =
4770                  simplelist(conf[__configinfo_struct[:default_value]])
4771              end
4772              if ( conf[__configinfo_struct[:current_value]] )
4773                conf[__configinfo_struct[:current_value]] =
4774                  simplelist(conf[__configinfo_struct[:current_value]])
4775              end
4776
4777            when /^(#{__numlistval_optkeys.join('|')})$/
4778              if ( __configinfo_struct[:default_value] \
4779                  && conf[__configinfo_struct[:default_value]] \
4780                  && conf[__configinfo_struct[:default_value]] =~ /^[0-9]/ )
4781                conf[__configinfo_struct[:default_value]] =
4782                  list(conf[__configinfo_struct[:default_value]])
4783              end
4784              if ( conf[__configinfo_struct[:current_value]] \
4785                  && conf[__configinfo_struct[:current_value]] =~ /^[0-9]/ )
4786                conf[__configinfo_struct[:current_value]] =
4787                  list(conf[__configinfo_struct[:current_value]])
4788              end
4789
4790            when /^(#{__tkvariable_optkeys.join('|')})$/
4791              if ( __configinfo_struct[:default_value] \
4792                  && conf[__configinfo_struct[:default_value]] )
4793                v = conf[__configinfo_struct[:default_value]]
4794                if v.empty?
4795                  conf[__configinfo_struct[:default_value]] = nil
4796                else
4797                  conf[__configinfo_struct[:default_value]] = TkVarAccess.new
4798                end
4799              end
4800              if ( conf[__configinfo_struct[:current_value]] )
4801                v = conf[__configinfo_struct[:current_value]]
4802                if v.empty?
4803                  conf[__configinfo_struct[:current_value]] = nil
4804                else
4805                  conf[__configinfo_struct[:current_value]] = TkVarAccess.new
4806                end
4807              end
4808
4809            else
4810              if ( __configinfo_struct[:default_value] \
4811                  && conf[__configinfo_struct[:default_value]] )
4812                if conf[__configinfo_struct[:default_value]].index('{')
4813                  conf[__configinfo_struct[:default_value]] =
4814                    tk_split_list(conf[__configinfo_struct[:default_value]])
4815                else
4816                  conf[__configinfo_struct[:default_value]] =
4817                    tk_tcl2ruby(conf[__configinfo_struct[:default_value]])
4818                end
4819              end
4820              if conf[__configinfo_struct[:current_value]]
4821                if conf[__configinfo_struct[:current_value]].index('{')
4822                  conf[__configinfo_struct[:current_value]] =
4823                    tk_split_list(conf[__configinfo_struct[:current_value]])
4824                else
4825                  conf[__configinfo_struct[:current_value]] =
4826                    tk_tcl2ruby(conf[__configinfo_struct[:current_value]])
4827                end
4828              end
4829            end
4830
4831            if ( __configinfo_struct[:alias] \
4832                && conf.size == __configinfo_struct[:alias] + 1 )
4833              if conf[__configinfo_struct[:alias]][0] == ?-
4834                conf[__configinfo_struct[:alias]] =
4835                  conf[__configinfo_struct[:alias]][1..-1]
4836              end
4837              ret[conf[0]] = conf[1]
4838            else
4839              ret[conf.shift] = conf
4840            end
4841          }
4842
4843          __font_optkeys.each{|optkey|
4844            optkey = optkey.to_s
4845            fontconf = ret[optkey]
4846            if fontconf.kind_of?(Array)
4847              ret.delete(optkey)
4848              ret.delete('latin' << optkey)
4849              ret.delete('ascii' << optkey)
4850              ret.delete('kanji' << optkey)
4851              fnt = fontconf[__configinfo_struct[:default_value]]
4852              if TkFont.is_system_font?(fnt)
4853                fontconf[__configinfo_struct[:default_value]] \
4854                  = TkNamedFont.new(fnt)
4855              end
4856              fontconf[__configinfo_struct[:current_value]] = fontobj(optkey)
4857              ret[optkey] = fontconf
4858            end
4859          }
4860
4861          __methodcall_optkeys.each{|optkey, m|
4862            ret[optkey.to_s] = ['', '', '', self.__send__(m)]
4863          }
4864
4865          ret
4866        end
4867      end
4868    end
4869  end
4870  private :__configinfo_core
4871
4872  def configinfo(slot = nil)
4873    if slot && TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
4874      begin
4875        __configinfo_core(slot)
4876      rescue
4877        Array.new(__configinfo_struct.values.max).unshift(slot.to_s)
4878      end
4879    else
4880      __configinfo_core(slot)
4881    end
4882  end
4883
4884  def current_configinfo(slot = nil)
4885    if TkComm::GET_CONFIGINFO_AS_ARRAY
4886      if slot
4887        org_slot = slot
4888        begin
4889          conf = configinfo(slot)
4890          if ( ! __configinfo_struct[:alias] \
4891              || conf.size > __configinfo_struct[:alias] + 1 )
4892            return {conf[0] => conf[-1]}
4893          end
4894          slot = conf[__configinfo_struct[:alias]]
4895        end while(org_slot != slot)
4896        fail RuntimeError,
4897          "there is a configure alias loop about '#{org_slot}'"
4898      else
4899        ret = {}
4900        configinfo().each{|cnf|
4901          if ( ! __configinfo_struct[:alias] \
4902              || cnf.size > __configinfo_struct[:alias] + 1 )
4903            ret[cnf[0]] = cnf[-1]
4904          end
4905        }
4906        ret
4907      end
4908    else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
4909      ret = {}
4910      configinfo(slot).each{|key, cnf|
4911        ret[key] = cnf[-1] if cnf.kind_of?(Array)
4912      }
4913      ret
4914    end
4915  end
4916end
4917
4918class TkObject<TkKernel
4919  extend  TkCore
4920  include Tk
4921  include TkConfigMethod
4922  include TkBindCore
4923
4924### --> definition is moved to TkUtil module
4925#  def path
4926#    @path
4927#  end
4928
4929  def epath
4930    @path
4931  end
4932
4933  def to_eval
4934    @path
4935  end
4936
4937  def tk_send(cmd, *rest)
4938    tk_call(path, cmd, *rest)
4939  end
4940  def tk_send_without_enc(cmd, *rest)
4941    tk_call_without_enc(path, cmd, *rest)
4942  end
4943  def tk_send_with_enc(cmd, *rest)
4944    tk_call_with_enc(path, cmd, *rest)
4945  end
4946  # private :tk_send, :tk_send_without_enc, :tk_send_with_enc
4947
4948  def tk_send_to_list(cmd, *rest)
4949    tk_call_to_list(path, cmd, *rest)
4950  end
4951  def tk_send_to_list_without_enc(cmd, *rest)
4952    tk_call_to_list_without_enc(path, cmd, *rest)
4953  end
4954  def tk_send_to_list_with_enc(cmd, *rest)
4955    tk_call_to_list_with_enc(path, cmd, *rest)
4956  end
4957  def tk_send_to_simplelist(cmd, *rest)
4958    tk_call_to_simplelist(path, cmd, *rest)
4959  end
4960  def tk_send_to_simplelist_without_enc(cmd, *rest)
4961    tk_call_to_simplelist_without_enc(path, cmd, *rest)
4962  end
4963  def tk_send_to_simplelist_with_enc(cmd, *rest)
4964    tk_call_to_simplelist_with_enc(path, cmd, *rest)
4965  end
4966
4967  def method_missing(id, *args)
4968    name = id.id2name
4969    case args.length
4970    when 1
4971      if name[-1] == ?=
4972        configure name[0..-2], args[0]
4973        args[0]
4974      else
4975        configure name, args[0]
4976        self
4977      end
4978    when 0
4979      begin
4980        cget(name)
4981      rescue
4982        if self.kind_of?(TkWindow) && name != "to_ary" && name != "to_str"
4983          fail NameError,
4984               "unknown option '#{id}' for #{self.inspect} (deleted widget?)"
4985        else
4986          super(id, *args)
4987        end
4988#        fail NameError,
4989#             "undefined local variable or method `#{name}' for #{self.to_s}",
4990#             error_at
4991      end
4992    else
4993      super(id, *args)
4994#      fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at
4995    end
4996  end
4997
4998=begin
4999  def [](id)
5000    cget(id)
5001  end
5002
5003  def []=(id, val)
5004    configure(id, val)
5005    val
5006  end
5007=end
5008
5009  def event_generate(context, keys=nil)
5010    if context.kind_of?(TkEvent::Event)
5011      context.generate(self, ((keys)? keys: {}))
5012    elsif keys
5013      #tk_call('event', 'generate', path,
5014      #       "<#{tk_event_sequence(context)}>", *hash_kv(keys))
5015      tk_call_without_enc('event', 'generate', path,
5016                          "<#{tk_event_sequence(context)}>",
5017                          *hash_kv(keys, true))
5018    else
5019      #tk_call('event', 'generate', path, "<#{tk_event_sequence(context)}>")
5020      tk_call_without_enc('event', 'generate', path,
5021                          "<#{tk_event_sequence(context)}>")
5022    end
5023  end
5024
5025  def tk_trace_variable(v)
5026    #unless v.kind_of?(TkVariable)
5027    #  fail(ArgumentError, "type error (#{v.class}); must be TkVariable object")
5028    #end
5029    v
5030  end
5031  private :tk_trace_variable
5032
5033  def destroy
5034    #tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id
5035  end
5036end
5037
5038
5039class TkWindow<TkObject
5040  include TkWinfo
5041  extend TkBindCore
5042  include Tk::Wm_for_General
5043  include Tk::Busy
5044
5045  @@WIDGET_INSPECT_FULL = false
5046  def TkWindow._widget_inspect_full_?
5047    @@WIDGET_INSPECT_FULL
5048  end
5049  def TkWindow._widget_inspect_full_=(mode)
5050    @@WIDGET_INSPECT_FULL = (mode && true) || false
5051  end
5052
5053  TkCommandNames = [].freeze
5054  ## ==> If TkCommandNames[0] is a string (not a null string),
5055  ##     assume the string is a Tcl/Tk's create command of the widget class.
5056  WidgetClassName = ''.freeze
5057  # WidgetClassNames[WidgetClassName] = self
5058  ## ==> If self is a widget class, entry to the WidgetClassNames table.
5059  def self.to_eval
5060    self::WidgetClassName
5061  end
5062
5063  def initialize(parent=nil, keys=nil)
5064    if parent.kind_of? Hash
5065      keys = _symbolkey2str(parent)
5066      parent = keys.delete('parent')
5067      widgetname = keys.delete('widgetname')
5068      install_win(if parent then parent.path end, widgetname)
5069      without_creating = keys.delete('without_creating')
5070      # if without_creating && !widgetname
5071      #   fail ArgumentError,
5072      #        "if set 'without_creating' to true, need to define 'widgetname'"
5073      # end
5074    elsif keys
5075      keys = _symbolkey2str(keys)
5076      widgetname = keys.delete('widgetname')
5077      install_win(if parent then parent.path end, widgetname)
5078      without_creating = keys.delete('without_creating')
5079      # if without_creating && !widgetname
5080      #   fail ArgumentError,
5081      #        "if set 'without_creating' to true, need to define 'widgetname'"
5082      # end
5083    else
5084      install_win(if parent then parent.path end)
5085    end
5086    if self.method(:create_self).arity == 0
5087      p 'create_self has no arg' if $DEBUG
5088      create_self unless without_creating
5089      if keys
5090        # tk_call @path, 'configure', *hash_kv(keys)
5091        configure(keys)
5092      end
5093    else
5094      p 'create_self has args' if $DEBUG
5095      fontkeys = {}
5096      methodkeys = {}
5097      if keys
5098        #['font', 'kanjifont', 'latinfont', 'asciifont'].each{|key|
5099        #  fontkeys[key] = keys.delete(key) if keys.key?(key)
5100        #}
5101        __font_optkeys.each{|key|
5102          fkey = key.to_s
5103          fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey)
5104
5105          fkey = "kanji#{key}"
5106          fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey)
5107
5108          fkey = "latin#{key}"
5109          fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey)
5110
5111          fkey = "ascii#{key}"
5112          fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey)
5113        }
5114
5115        __optkey_aliases.each{|alias_name, real_name|
5116          alias_name = alias_name.to_s
5117          if keys.has_key?(alias_name)
5118            keys[real_name.to_s] = keys.delete(alias_name)
5119          end
5120        }
5121
5122        __methodcall_optkeys.each{|key|
5123          key = key.to_s
5124          methodkeys[key] = keys.delete(key) if keys.key?(key)
5125        }
5126
5127        __ruby2val_optkeys.each{|key, method|
5128          key = key.to_s
5129          keys[key] = method.call(keys[key]) if keys.has_key?(key)
5130        }
5131      end
5132      if without_creating && keys
5133        #configure(keys)
5134        configure(__conv_keyonly_opts(keys))
5135      else
5136        #create_self(keys)
5137        create_self(__conv_keyonly_opts(keys))
5138      end
5139      font_configure(fontkeys) unless fontkeys.empty?
5140      configure(methodkeys) unless methodkeys.empty?
5141    end
5142  end
5143
5144  def create_self(keys)
5145    # may need to override
5146    begin
5147      cmd = self.class::TkCommandNames[0]
5148      fail unless (cmd.kind_of?(String) && cmd.length > 0)
5149    rescue
5150      fail RuntimeError, "class #{self.class} may be an abstract class"
5151    end
5152
5153    if keys and keys != None
5154      unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
5155        tk_call_without_enc(cmd, @path, *hash_kv(keys, true))
5156      else
5157        begin
5158          tk_call_without_enc(cmd, @path, *hash_kv(keys, true))
5159        rescue => e
5160          tk_call_without_enc(cmd, @path)
5161          keys = __check_available_configure_options(keys)
5162          unless keys.empty?
5163            begin
5164              # try to configure
5165              configure(keys)
5166            rescue
5167              # fail => includes options adaptable when creattion only?
5168              begin
5169                tk_call_without_enc('destroy', @path)
5170              rescue
5171                # cannot rescue options error
5172                fail e
5173              else
5174                # re-create widget
5175                tk_call_without_enc(cmd, @path, *hash_kv(keys, true))
5176              end
5177            end
5178          end
5179        end
5180      end
5181    else
5182      tk_call_without_enc(cmd, @path)
5183    end
5184  end
5185  private :create_self
5186
5187  def inspect
5188    if @@WIDGET_INSPECT_FULL
5189      super
5190    else
5191      str = super
5192      str[0..(str.index(' '))] << '@path=' << @path.inspect << '>'
5193    end
5194  end
5195
5196  def exist?
5197    TkWinfo.exist?(self)
5198  end
5199
5200  def bind_class
5201    @db_class || self.class()
5202  end
5203
5204  def database_classname
5205    TkWinfo.classname(self)
5206  end
5207  def database_class
5208    name = database_classname()
5209    if WidgetClassNames[name]
5210      WidgetClassNames[name]
5211    else
5212      TkDatabaseClass.new(name)
5213    end
5214  end
5215  def self.database_classname
5216    self::WidgetClassName
5217  end
5218  def self.database_class
5219    WidgetClassNames[self::WidgetClassName]
5220  end
5221
5222  def pack(keys = nil)
5223    #tk_call_without_enc('pack', epath, *hash_kv(keys, true))
5224    if keys
5225      TkPack.configure(self, keys)
5226    else
5227      TkPack.configure(self)
5228    end
5229    self
5230  end
5231
5232  def pack_in(target, keys = nil)
5233    if keys
5234      keys = keys.dup
5235      keys['in'] = target
5236    else
5237      keys = {'in'=>target}
5238    end
5239    #tk_call 'pack', epath, *hash_kv(keys)
5240    TkPack.configure(self, keys)
5241    self
5242  end
5243
5244  def pack_forget
5245    #tk_call_without_enc('pack', 'forget', epath)
5246    TkPack.forget(self)
5247    self
5248  end
5249  alias unpack pack_forget
5250
5251  def pack_config(slot, value=None)
5252    #if slot.kind_of? Hash
5253    #  tk_call 'pack', 'configure', epath, *hash_kv(slot)
5254    #else
5255    #  tk_call 'pack', 'configure', epath, "-#{slot}", value
5256    #end
5257    if slot.kind_of? Hash
5258      TkPack.configure(self, slot)
5259    else
5260      TkPack.configure(self, slot=>value)
5261    end
5262  end
5263  alias pack_configure pack_config
5264
5265  def pack_info()
5266    #ilist = list(tk_call('pack', 'info', epath))
5267    #info = {}
5268    #while key = ilist.shift
5269    #  info[key[1..-1]] = ilist.shift
5270    #end
5271    #return info
5272    TkPack.info(self)
5273  end
5274
5275  def pack_propagate(mode=None)
5276    #if mode == None
5277    #  bool(tk_call('pack', 'propagate', epath))
5278    #else
5279    #  tk_call('pack', 'propagate', epath, mode)
5280    #  self
5281    #end
5282    if mode == None
5283      TkPack.propagate(self)
5284    else
5285      TkPack.propagate(self, mode)
5286      self
5287    end
5288  end
5289
5290  def pack_slaves()
5291    #list(tk_call('pack', 'slaves', epath))
5292    TkPack.slaves(self)
5293  end
5294
5295  def grid(keys = nil)
5296    #tk_call 'grid', epath, *hash_kv(keys)
5297    if keys
5298      TkGrid.configure(self, keys)
5299    else
5300      TkGrid.configure(self)
5301    end
5302    self
5303  end
5304
5305  def grid_in(target, keys = nil)
5306    if keys
5307      keys = keys.dup
5308      keys['in'] = target
5309    else
5310      keys = {'in'=>target}
5311    end
5312    #tk_call 'grid', epath, *hash_kv(keys)
5313    TkGrid.configure(self, keys)
5314    self
5315  end
5316
5317  def grid_anchor(anchor=None)
5318    if anchor == None
5319      TkGrid.anchor(self)
5320    else
5321      TkGrid.anchor(self, anchor)
5322      self
5323    end
5324  end
5325
5326  def grid_forget
5327    #tk_call('grid', 'forget', epath)
5328    TkGrid.forget(self)
5329    self
5330  end
5331  alias ungrid grid_forget
5332
5333  def grid_bbox(*args)
5334    #list(tk_call('grid', 'bbox', epath, *args))
5335    TkGrid.bbox(self, *args)
5336  end
5337
5338  def grid_config(slot, value=None)
5339    #if slot.kind_of? Hash
5340    #  tk_call 'grid', 'configure', epath, *hash_kv(slot)
5341    #else
5342    #  tk_call 'grid', 'configure', epath, "-#{slot}", value
5343    #end
5344    if slot.kind_of? Hash
5345      TkGrid.configure(self, slot)
5346    else
5347      TkGrid.configure(self, slot=>value)
5348    end
5349  end
5350  alias grid_configure grid_config
5351
5352  def grid_columnconfig(index, keys)
5353    #tk_call('grid', 'columnconfigure', epath, index, *hash_kv(keys))
5354    TkGrid.columnconfigure(self, index, keys)
5355  end
5356  alias grid_columnconfigure grid_columnconfig
5357
5358  def grid_rowconfig(index, keys)
5359    #tk_call('grid', 'rowconfigure', epath, index, *hash_kv(keys))
5360    TkGrid.rowconfigure(self, index, keys)
5361  end
5362  alias grid_rowconfigure grid_rowconfig
5363
5364  def grid_columnconfiginfo(index, slot=nil)
5365    #if slot
5366    #  tk_call('grid', 'columnconfigure', epath, index, "-#{slot}").to_i
5367    #else
5368    #  ilist = list(tk_call('grid', 'columnconfigure', epath, index))
5369    #  info = {}
5370    #  while key = ilist.shift
5371    #   info[key[1..-1]] = ilist.shift
5372    #  end
5373    #  info
5374    #end
5375    TkGrid.columnconfiginfo(self, index, slot)
5376  end
5377
5378  def grid_rowconfiginfo(index, slot=nil)
5379    #if slot
5380    #  tk_call('grid', 'rowconfigure', epath, index, "-#{slot}").to_i
5381    #else
5382    #  ilist = list(tk_call('grid', 'rowconfigure', epath, index))
5383    #  info = {}
5384    #  while key = ilist.shift
5385    #   info[key[1..-1]] = ilist.shift
5386    #  end
5387    #  info
5388    #end
5389    TkGrid.rowconfiginfo(self, index, slot)
5390  end
5391
5392  def grid_column(index, keys=nil)
5393    if keys.kind_of?(Hash)
5394      grid_columnconfigure(index, keys)
5395    else
5396      grid_columnconfiginfo(index, keys)
5397    end
5398  end
5399
5400  def grid_row(index, keys=nil)
5401    if keys.kind_of?(Hash)
5402      grid_rowconfigure(index, keys)
5403    else
5404      grid_rowconfiginfo(index, keys)
5405    end
5406  end
5407
5408  def grid_info()
5409    #list(tk_call('grid', 'info', epath))
5410    TkGrid.info(self)
5411  end
5412
5413  def grid_location(x, y)
5414    #list(tk_call('grid', 'location', epath, x, y))
5415    TkGrid.location(self, x, y)
5416  end
5417
5418  def grid_propagate(mode=None)
5419    #if mode == None
5420    #  bool(tk_call('grid', 'propagate', epath))
5421    #else
5422    #  tk_call('grid', 'propagate', epath, mode)
5423    #  self
5424    #end
5425    if mode == None
5426      TkGrid.propagate(self)
5427    else
5428      TkGrid.propagate(self, mode)
5429      self
5430    end
5431  end
5432
5433  def grid_remove()
5434    #tk_call 'grid', 'remove', epath
5435    TkGrid.remove(self)
5436    self
5437  end
5438
5439  def grid_size()
5440    #list(tk_call('grid', 'size', epath))
5441    TkGrid.size(self)
5442  end
5443
5444  def grid_slaves(keys = nil)
5445    #list(tk_call('grid', 'slaves', epath, *hash_kv(args)))
5446    TkGrid.slaves(self, keys)
5447  end
5448
5449  def place(keys)
5450    #tk_call 'place', epath, *hash_kv(keys)
5451    TkPlace.configure(self, keys)
5452    self
5453  end
5454
5455  def place_in(target, keys = nil)
5456    if keys
5457      keys = keys.dup
5458      keys['in'] = target
5459    else
5460      keys = {'in'=>target}
5461    end
5462    #tk_call 'place', epath, *hash_kv(keys)
5463    TkPlace.configure(self, keys)
5464    self
5465  end
5466
5467  def  place_forget
5468    #tk_call 'place', 'forget', epath
5469    TkPlace.forget(self)
5470    self
5471  end
5472  alias unplace place_forget
5473
5474  def place_config(slot, value=None)
5475    #if slot.kind_of? Hash
5476    #  tk_call 'place', 'configure', epath, *hash_kv(slot)
5477    #else
5478    #  tk_call 'place', 'configure', epath, "-#{slot}", value
5479    #end
5480    TkPlace.configure(self, slot, value)
5481  end
5482  alias place_configure place_config
5483
5484  def place_configinfo(slot = nil)
5485    # for >= Tk8.4a2 ?
5486    #if slot
5487    #  conf = tk_split_list(tk_call('place', 'configure', epath, "-#{slot}") )
5488    #  conf[0] = conf[0][1..-1]
5489    #  conf
5490    #else
5491    #  tk_split_simplelist(tk_call('place',
5492    #                             'configure', epath)).collect{|conflist|
5493    #   conf = tk_split_simplelist(conflist)
5494    #   conf[0] = conf[0][1..-1]
5495    #   conf
5496    #  }
5497    #end
5498    TkPlace.configinfo(self, slot)
5499  end
5500
5501  def place_info()
5502    #ilist = list(tk_call('place', 'info', epath))
5503    #info = {}
5504    #while key = ilist.shift
5505    #  info[key[1..-1]] = ilist.shift
5506    #end
5507    #return info
5508    TkPlace.info(self)
5509  end
5510
5511  def place_slaves()
5512    #list(tk_call('place', 'slaves', epath))
5513    TkPlace.slaves(self)
5514  end
5515
5516  def set_focus(force=false)
5517    if force
5518      tk_call_without_enc('focus', '-force', path)
5519    else
5520      tk_call_without_enc('focus', path)
5521    end
5522    self
5523  end
5524  alias focus set_focus
5525
5526  def grab(opt = nil)
5527    unless opt
5528      tk_call_without_enc('grab', 'set', path)
5529      return self
5530    end
5531
5532    case opt
5533    when 'set', :set
5534      tk_call_without_enc('grab', 'set', path)
5535      return self
5536    when 'global', :global
5537      #return(tk_call('grab', 'set', '-global', path))
5538      tk_call_without_enc('grab', 'set', '-global', path)
5539      return self
5540    when 'release', :release
5541      #return tk_call('grab', 'release', path)
5542      tk_call_without_enc('grab', 'release', path)
5543      return self
5544    when 'current', :current
5545      return window(tk_call_without_enc('grab', 'current', path))
5546    when 'status', :status
5547      return tk_call_without_enc('grab', 'status', path)
5548    else
5549      return tk_call_without_enc('grab', opt, path)
5550    end
5551  end
5552
5553  def grab_current
5554    grab('current')
5555  end
5556  alias current_grab grab_current
5557  def grab_release
5558    grab('release')
5559  end
5560  alias release_grab grab_release
5561  def grab_set
5562    grab('set')
5563  end
5564  alias set_grab grab_set
5565  def grab_set_global
5566    grab('global')
5567  end
5568  alias set_global_grab grab_set_global
5569  def grab_status
5570    grab('status')
5571  end
5572
5573  def lower(below=None)
5574    # below = below.epath if below.kind_of?(TkObject)
5575    below = _epath(below)
5576    tk_call 'lower', epath, below
5577    self
5578  end
5579  alias lower_window lower
5580  def raise(above=None)
5581    #above = above.epath if above.kind_of?(TkObject)
5582    above = _epath(above)
5583    tk_call 'raise', epath, above
5584    self
5585  end
5586  alias raise_window raise
5587
5588  def command(cmd=nil, &b)
5589    if cmd
5590      configure_cmd('command', cmd)
5591    elsif b
5592      configure_cmd('command', Proc.new(&b))
5593    else
5594      cget('command')
5595    end
5596  end
5597
5598  def colormodel(model=None)
5599    tk_call('tk', 'colormodel', path, model)
5600    self
5601  end
5602
5603  def caret(keys=nil)
5604    TkXIM.caret(path, keys)
5605  end
5606
5607  def destroy
5608    super
5609    children = []
5610    rexp = /^#{self.path}\.[^.]+$/
5611    TkCore::INTERP.tk_windows.each{|path, obj|
5612      children << [path, obj] if path =~ rexp
5613    }
5614    if defined?(@cmdtbl)
5615      for id in @cmdtbl
5616        uninstall_cmd id
5617      end
5618    end
5619
5620    children.each{|path, obj|
5621      obj.instance_eval{
5622        if defined?(@cmdtbl)
5623          for id in @cmdtbl
5624            uninstall_cmd id
5625          end
5626        end
5627      }
5628      TkCore::INTERP.tk_windows.delete(path)
5629    }
5630
5631    begin
5632      tk_call_without_enc('destroy', epath)
5633    rescue
5634    end
5635    uninstall_win
5636  end
5637
5638  def wait_visibility(on_thread = true)
5639    if $SAFE >= 4
5640      fail SecurityError, "can't wait visibility at $SAFE >= 4"
5641    end
5642    on_thread &= (Thread.list.size != 1)
5643    if on_thread
5644      INTERP._thread_tkwait('visibility', path)
5645    else
5646      INTERP._invoke('tkwait', 'visibility', path)
5647    end
5648  end
5649  def eventloop_wait_visibility
5650    wait_visibility(false)
5651  end
5652  def thread_wait_visibility
5653    wait_visibility(true)
5654  end
5655  alias wait wait_visibility
5656  alias tkwait wait_visibility
5657  alias eventloop_wait eventloop_wait_visibility
5658  alias eventloop_tkwait eventloop_wait_visibility
5659  alias eventloop_tkwait_visibility eventloop_wait_visibility
5660  alias thread_wait thread_wait_visibility
5661  alias thread_tkwait thread_wait_visibility
5662  alias thread_tkwait_visibility thread_wait_visibility
5663
5664  def wait_destroy(on_thread = true)
5665    if $SAFE >= 4
5666      fail SecurityError, "can't wait destroy at $SAFE >= 4"
5667    end
5668    on_thread &= (Thread.list.size != 1)
5669    if on_thread
5670      INTERP._thread_tkwait('window', epath)
5671    else
5672      INTERP._invoke('tkwait', 'window', epath)
5673    end
5674  end
5675  alias wait_window wait_destroy
5676  def eventloop_wait_destroy
5677    wait_destroy(false)
5678  end
5679  alias eventloop_wait_window eventloop_wait_destroy
5680  def thread_wait_destroy
5681    wait_destroy(true)
5682  end
5683  alias thread_wait_window thread_wait_destroy
5684
5685  alias tkwait_destroy wait_destroy
5686  alias tkwait_window wait_destroy
5687
5688  alias eventloop_tkwait_destroy eventloop_wait_destroy
5689  alias eventloop_tkwait_window eventloop_wait_destroy
5690
5691  alias thread_tkwait_destroy thread_wait_destroy
5692  alias thread_tkwait_window thread_wait_destroy
5693
5694  def bindtags(taglist=nil)
5695    if taglist
5696      fail ArgumentError, "taglist must be Array" unless taglist.kind_of? Array
5697      tk_call('bindtags', path, taglist)
5698      taglist
5699    else
5700      list(tk_call('bindtags', path)).collect{|tag|
5701        if tag.kind_of?(String)
5702          if cls = WidgetClassNames[tag]
5703            cls
5704          elsif btag = TkBindTag.id2obj(tag)
5705            btag
5706          else
5707            tag
5708          end
5709        else
5710          tag
5711        end
5712      }
5713    end
5714  end
5715
5716  def bindtags=(taglist)
5717    bindtags(taglist)
5718    taglist
5719  end
5720
5721  def bindtags_shift
5722    taglist = bindtags
5723    tag = taglist.shift
5724    bindtags(taglist)
5725    tag
5726  end
5727
5728  def bindtags_unshift(tag)
5729    bindtags(bindtags().unshift(tag))
5730  end
5731end
5732TkWidget = TkWindow
5733
5734# freeze core modules
5735#TclTkLib.freeze
5736#TclTkIp.freeze
5737#TkUtil.freeze
5738#TkKernel.freeze
5739#TkComm.freeze
5740#TkComm::Event.freeze
5741#TkCore.freeze
5742#Tk.freeze
5743
5744module Tk
5745  RELEASE_DATE = '2010-06-03'.freeze
5746
5747  autoload :AUTO_PATH,        'tk/variable'
5748  autoload :TCL_PACKAGE_PATH, 'tk/variable'
5749  autoload :PACKAGE_PATH,     'tk/variable'
5750  autoload :TCL_LIBRARY_PATH, 'tk/variable'
5751  autoload :LIBRARY_PATH,     'tk/variable'
5752  autoload :TCL_PRECISION,    'tk/variable'
5753end
5754
5755# call setup script for Tk extension libraries (base configuration)
5756begin
5757  require 'tkextlib/version.rb'
5758  require 'tkextlib/setup.rb'
5759rescue LoadError
5760  # ignore
5761end
5762