ext/tk/lib/tk.rb


DEFINITIONS

This source file includes following functions.


   1  #
   2  #               tk.rb - Tk interface module using tcltklib
   3  #                       $Date: 2002/06/28 14:40:25 $
   4  #                       by Yukihiro Matsumoto <matz@netlab.jp>
   5  
   6  # use Shigehiro's tcltklib
   7  require "tcltklib"
   8  require "tkutil"
   9  
  10  module TkComm
  11    WidgetClassNames = {}
  12  
  13    None = Object.new
  14    def None.to_s
  15      'None'
  16    end
  17  
  18    Tk_CMDTBL = {}
  19    Tk_WINDOWS = {}
  20  
  21    def error_at
  22      frames = caller()
  23      frames.delete_if do |c|
  24        c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+!
  25      end
  26      frames
  27    end
  28    private :error_at
  29  
  30    def _genobj_for_tkwidget(path)
  31      return TkRoot.new if path == '.'
  32  
  33      begin
  34        tk_class = TkCore::INTERP._invoke('winfo', 'class', path)
  35      rescue
  36        return path
  37      end
  38  
  39      ruby_class = WidgetClassNames[tk_class]
  40      gen_class_name = ruby_class.name + 'GeneratedOnTk'
  41      unless Object.const_defined? gen_class_name
  42        eval "class #{gen_class_name}<#{ruby_class.name}
  43                def initialize(path)
  44                  @path=path
  45                  Tk_WINDOWS[@path] = self
  46                end
  47              end"
  48      end
  49      eval "#{gen_class_name}.new('#{path}')"
  50    end
  51  
  52    def tk_tcl2ruby(val)
  53      if val =~ /^rb_out (c\d+)/
  54        return Tk_CMDTBL[$1]
  55      end
  56      if val.include? ?\s
  57        return val.split.collect{|v| tk_tcl2ruby(v)}
  58      end
  59      case val
  60      when /^@font/
  61        TkFont.get_obj(val)
  62      when /^-?\d+$/
  63        val.to_i
  64      when /^\./
  65        Tk_WINDOWS[val] ? Tk_WINDOWS[val] : _genobj_for_tkwidget(val)
  66      when / /
  67        val.split.collect{|elt|
  68          tk_tcl2ruby(elt)
  69        }
  70      when /^-?\d+\.\d*$/
  71        val.to_f
  72      else
  73        val
  74      end
  75    end
  76  
  77    def tk_split_list(str)
  78      return [] if str == ""
  79      idx = str.index('{')
  80      while idx and idx > 0 and str[idx-1] == ?\\
  81        idx = str.index('{', idx+1)
  82      end
  83      return tk_tcl2ruby(str) unless idx
  84  
  85      list = tk_tcl2ruby(str[0,idx])
  86      list = [] if list == ""
  87      str = str[idx+1..-1]
  88      i = -1
  89      brace = 1
  90      str.each_byte {|c|
  91        i += 1
  92        brace += 1 if c == ?{
  93        brace -= 1 if c == ?}
  94        break if brace == 0
  95      }
  96      if str[0, i] == ' '
  97        list.push ' '
  98      else
  99        list.push tk_split_list(str[0, i])
 100      end
 101      list += tk_split_list(str[i+1..-1])
 102      list
 103    end
 104  
 105    def tk_split_simplelist(str)
 106      return [] if str == ""
 107      idx = str.index('{')
 108      while idx and idx > 0 and str[idx-1] == ?\\
 109        idx = str.index('{', idx+1)
 110      end
 111      return str.split unless idx
 112  
 113      list = str[0,idx].split
 114      str = str[idx+1..-1]
 115      i = -1
 116      brace = 1
 117      str.each_byte {|c|
 118        i += 1
 119        brace += 1 if c == ?{
 120        brace -= 1 if c == ?}
 121        break if brace == 0
 122      }
 123      if i == 0
 124        list.push ''
 125      elsif str[0, i] == ' '
 126        list.push ' '
 127      else
 128        list.push str[0..i-1]
 129      end
 130      list += tk_split_simplelist(str[i+1..-1])
 131      list
 132    end
 133    private :tk_tcl2ruby, :tk_split_list, :tk_split_simplelist
 134  
 135    def _symbolkey2str(keys)
 136      h = {}
 137      keys.each{|key,value| h[key.to_s] = value}
 138      h
 139    end
 140    private :_symbolkey2str
 141  
 142    def hash_kv(keys)
 143      conf = []
 144      if keys and keys != None
 145        for k, v in keys
 146           conf.push("-#{k}")
 147           conf.push(v)
 148        end
 149      end
 150      conf
 151    end
 152    private :hash_kv
 153  
 154    def array2tk_list(ary)
 155      ary.collect{|e|
 156        if e.kind_of? Array
 157          "{#{array2tk_list(e)}}"
 158        elsif e.kind_of? Hash
 159          "{#{e.to_a.collect{|ee| array2tk_list(ee)}.join(' ')}}"
 160        else
 161          s = _get_eval_string(e)
 162          (s.index(/\s/))? "{#{s}}": s
 163        end
 164      }.join(" ")
 165    end
 166    private :array2tk_list
 167  
 168    def bool(val)
 169      case val
 170      when "1", 1, 'yes', 'true'
 171        TRUE
 172      else
 173        FALSE
 174      end
 175    end
 176    def number(val)
 177      case val
 178      when /^-?\d+$/
 179        val.to_i
 180      when /^-?\d+\.\d*$/
 181        val.to_f
 182      else
 183        val
 184      end
 185    end
 186    def string(val)
 187      if val == "{}"
 188        ''
 189      elsif val[0] == ?{
 190        val[1..-2]
 191      else
 192        val
 193      end
 194    end
 195    def list(val)
 196      tk_split_list(val).to_a
 197    end
 198    def window(val)
 199      Tk_WINDOWS[val]
 200    end
 201    def procedure(val)
 202      if val =~ /^rb_out (c\d+)/
 203        Tk_CMDTBL[$1]
 204      else
 205        nil
 206      end
 207    end
 208    private :bool, :number, :string, :list, :window, :procedure
 209  
 210    def _get_eval_string(str)
 211      return nil if str == None
 212      if str.kind_of?(String)
 213        # do nothing
 214      elsif str.kind_of?(Symbol)
 215        str = str.id2name
 216      elsif str.kind_of?(Hash)
 217        str = hash_kv(str).join(" ")
 218      elsif str.kind_of?(Array)
 219        str = array2tk_list(str)
 220      elsif str.kind_of?(Proc)
 221        str = install_cmd(str)
 222      elsif str == nil
 223        str = ""
 224      elsif str == false
 225        str = "0"
 226      elsif str == true
 227        str = "1"
 228      elsif (str.respond_to?(:to_eval))
 229        str = str.to_eval()
 230      else
 231        str = str.to_s()
 232      end
 233      return str
 234    end
 235    private :_get_eval_string
 236  
 237    def ruby2tcl(v)
 238      if v.kind_of?(Hash)
 239        v = hash_kv(v)
 240        v.flatten!
 241        v.collect{|e|ruby2tcl(e)}
 242      else
 243        _get_eval_string(v)
 244      end
 245    end
 246    private :ruby2tcl
 247  
 248    Tk_IDs = [0, 0]               # [0]-cmdid, [1]-winid
 249    def _curr_cmd_id
 250      id = format("c%.4d", Tk_IDs[0])
 251    end
 252    def _next_cmd_id
 253      id = _curr_cmd_id
 254      Tk_IDs[0] += 1
 255      id
 256    end
 257    def install_cmd(cmd)
 258      return '' if cmd == ''
 259      id = _next_cmd_id
 260      Tk_CMDTBL[id] = cmd
 261      @cmdtbl = [] unless @cmdtbl
 262      @cmdtbl.push id
 263      return format("rb_out %s", id);
 264    end
 265    def uninstall_cmd(id)
 266      id = $1 if /rb_out (c\d+)/ =~ id
 267      Tk_CMDTBL[id] = nil
 268    end
 269    private :install_cmd, :uninstall_cmd
 270  
 271    def install_win(ppath,name=nil)
 272      if !name or name == ''
 273        name = format("w%.4d", Tk_IDs[1])
 274        Tk_IDs[1] += 1
 275      end
 276      if !ppath or ppath == "."
 277        @path = format(".%s", name);
 278      else
 279        @path = format("%s.%s", ppath, name)
 280      end
 281      Tk_WINDOWS[@path] = self
 282    end
 283  
 284    def uninstall_win()
 285      Tk_WINDOWS[@path] = nil
 286    end
 287  
 288    class Event
 289      def initialize(seq,a,b,c,d,f,h,k,m,o,p,s,t,w,x,y,
 290                     aa,bb,dd,ee,kk,nn,rr,ss,tt,ww,xx,yy)
 291        @serial = seq
 292        @above = a
 293        @num = b
 294        @count = c
 295        @detail = d
 296        @focus = (f == 1)
 297        @height = h
 298        @keycode = k
 299        @mode = m
 300        @override = (o == 1)
 301        @place = p
 302        @state = s
 303        @time = t
 304        @width = w
 305        @x = x
 306        @y = y
 307        @char = aa
 308        @borderwidth = bb
 309        @wheel_delta = dd
 310        @send_event = (ee == 1)
 311        @keysym = kk
 312        @keysym_num = nn
 313        @rootwin_id = rr
 314        @subwindow = ss
 315        @type = tt
 316        @widget = ww
 317        @x_root = xx
 318        @y_root = yy
 319      end
 320      attr :serial
 321      attr :above
 322      attr :num
 323      attr :count
 324      attr :detail
 325      attr :focus
 326      attr :height
 327      attr :keycode
 328      attr :mode
 329      attr :override
 330      attr :place
 331      attr :state
 332      attr :time
 333      attr :width
 334      attr :x
 335      attr :y
 336      attr :char
 337      attr :borderwidth
 338      attr :wheel_delta
 339      attr :send_event
 340      attr :keysym
 341      attr :keysym_num
 342      attr :rootwin_id
 343      attr :subwindow
 344      attr :type
 345      attr :widget
 346      attr :x_root
 347      attr :y_root
 348    end
 349  
 350    def install_bind(cmd, args=nil)
 351      if args
 352        id = install_cmd(proc{|*arg|
 353          TkUtil.eval_cmd cmd, *arg
 354        })
 355        id + " " + args
 356      else
 357        id = install_cmd(proc{|arg|
 358          TkUtil.eval_cmd cmd, Event.new(*arg)
 359        })
 360        id + ' %# %a %b %c %d %f %h %k %m %o %p %s %t %w %x %y' + 
 361             ' %A %B %D %E %K %N %R %S %T %W %X %Y'
 362      end
 363    end
 364  
 365    def tk_event_sequence(context)
 366      if context.kind_of? TkVirtualEvent
 367        context = context.path
 368      end
 369      if context.kind_of? Array
 370        context = context.collect{|ev|
 371          if ev.kind_of? TkVirtualEvent
 372            ev.path
 373          else
 374            ev
 375          end
 376        }.join("><")
 377      end
 378      if /,/ =~ context
 379        context = context.split(/\s*,\s*/).join("><")
 380      else
 381        context
 382      end
 383    end
 384  
 385    def _bind_core(mode, what, context, cmd, args=nil)
 386      id = install_bind(cmd, args) if cmd
 387      begin
 388        tk_call(*(what + ["<#{tk_event_sequence(context)}>", mode + id]))
 389      rescue
 390        uninstall_cmd(id) if cmd
 391        fail
 392      end
 393    end
 394  
 395    def _bind(what, context, cmd, args=nil)
 396      _bind_core('', what, context, cmd, args)
 397    end
 398  
 399    def _bind_append(what, context, cmd, args=nil)
 400      _bind_core('+', what, context, cmd, args)
 401    end
 402  
 403    def _bind_remove(what, context)
 404      tk_call(*(what + ["<#{tk_event_sequence(context)}>", '']))
 405    end
 406  
 407    def _bindinfo(what, context=nil)
 408      if context
 409        tk_call(*what+["<#{tk_event_sequence(context)}>"]).collect {|cmdline|
 410          if cmdline =~ /^rb_out (c\d+)\s+(.*)$/
 411            [Tk_CMDTBL[$1], $2]
 412          else
 413            cmdline
 414          end
 415        }
 416      else
 417        tk_split_simplelist(tk_call(*what)).collect!{|seq|
 418          l = seq.scan(/<*[^<>]+>*/).collect!{|subseq|
 419            case (subseq)
 420            when /^<<[^<>]+>>$/
 421              TkVirtualEvent.getobj(subseq[1..-2])
 422            when /^<[^<>]+>$/
 423              subseq[1..-2]
 424            else
 425              subseq.split('')
 426            end
 427          }.flatten
 428          (l.size == 1) ? l[0] : l
 429        }
 430      end
 431    end
 432    private :install_bind, :tk_event_sequence, 
 433            :_bind_core, :_bind, :_bind_append, :_bind_remove, :_bindinfo
 434  
 435    def bind(tagOrClass, context, cmd=Proc.new, args=nil)
 436      _bind(["bind", tagOrClass], context, cmd, args)
 437    end
 438  
 439    def bind_append(tagOrClass, context, cmd=Proc.new, args=nil)
 440      _bind_append(["bind", tagOrClass], context, cmd, args)
 441    end
 442  
 443    def bind_remove(tagOrClass, context)
 444      _bind_remove(['bind', tagOrClass], context)
 445    end
 446  
 447    def bindinfo(tagOrClass, context=nil)
 448      _bindinfo(['bind', tagOrClass], context)
 449    end
 450  
 451    def bind_all(context, cmd=Proc.new, args=nil)
 452      _bind(['bind', 'all'], context, cmd, args)
 453    end
 454  
 455    def bind_append_all(context, cmd=Proc.new, args=nil)
 456      _bind_append(['bind', 'all'], context, cmd, args)
 457    end
 458  
 459    def bindinfo_all(context=nil)
 460      _bindinfo(['bind', 'all'], context)
 461    end
 462  
 463    def pack(*args)
 464      TkPack.configure(*args)
 465    end
 466  
 467    def grid(*args)
 468      TkGrid.configure(*args)
 469    end
 470  
 471    def update(idle=nil)
 472      if idle
 473        tk_call 'update', 'idletasks'
 474      else
 475        tk_call 'update'
 476      end
 477    end
 478  
 479  end
 480  
 481  module TkCore
 482    include TkComm
 483    extend TkComm
 484  
 485    INTERP = TclTkIp.new
 486  
 487    INTERP._invoke("proc", "rb_out", "args", <<-'EOL')
 488      regsub -all {!} $args {\\!} args
 489      regsub -all "{" $args "\\{" args
 490      if {[set st [catch {ruby [format "TkCore.callback %%Q!%s!" $args]} ret]] != 0} {
 491          return -code $st $ret
 492      } {
 493          return $ret
 494      }
 495    EOL
 496  
 497    EventFlag = TclTkLib::EventFlag
 498  
 499    def callback_break
 500      fail TkCallbackBreak, "Tk callback returns 'break' status"
 501    end
 502  
 503    def callback_continue
 504      fail TkCallbackContinue, "Tk callback returns 'continue' status"
 505    end
 506  
 507    def after(ms, cmd=Proc.new)
 508      myid = _curr_cmd_id
 509      cmdid = install_cmd(cmd)
 510      tk_call("after",ms,cmdid)
 511  #    return
 512  #    if false #defined? Thread
 513  #      Thread.start do
 514  #       ms = Float(ms)/1000
 515  #       ms = 10 if ms == 0
 516  #       sleep ms/1000
 517  #       cmd.call
 518  #      end
 519  #    else
 520  #      cmdid = install_cmd(cmd)
 521  #      tk_call("after",ms,cmdid)
 522  #    end
 523    end
 524  
 525    def after_idle(cmd=Proc.new)
 526      myid = _curr_cmd_id
 527      cmdid = install_cmd(cmd)
 528      tk_call('after','idle',cmdid)
 529    end
 530  
 531    def clock_clicks(ms=nil)
 532      if ms
 533        tk_call('clock','clicks','-milliseconds').to_i
 534      else
 535        tk_call('clock','clicks').to_i
 536      end
 537    end
 538  
 539    def clock_format(clk, form=nil)
 540      if form
 541        tk_call('clock','format',clk,'-format',form).to_i
 542      else
 543        tk_call('clock','format',clk).to_i
 544      end
 545    end
 546  
 547    def clock_formatGMT(clk, form=nil)
 548      if form
 549        tk_call('clock','format',clk,'-format',form,'-gmt','1').to_i
 550      else
 551        tk_call('clock','format',clk,'-gmt','1').to_i
 552      end
 553    end
 554  
 555    def clock_scan(str, base=nil)
 556      if base
 557        tk_call('clock','scan',str,'-base',base).to_i
 558      else
 559        tk_call('clock','scan',str).to_i
 560      end
 561    end
 562  
 563    def clock_scanGMT(str, base=nil)
 564      if base
 565        tk_call('clock','scan',str,'-base',base,'-gmt','1').to_i
 566      else
 567        tk_call('clock','scan',str,'-gmt','1').to_i
 568      end
 569    end
 570  
 571    def clock_seconds
 572      tk_call('clock','seconds').to_i
 573    end
 574  
 575    def TkCore.callback(arg)
 576      arg = Array(tk_split_list(arg))
 577      _get_eval_string(TkUtil.eval_cmd(Tk_CMDTBL[arg.shift], *arg))
 578    end
 579  
 580    def scaling(scale=nil)
 581      if scale
 582        tk_call('tk', 'scaling', scale)
 583      else
 584        Float(number(tk_call('tk', 'scaling')))
 585      end
 586    end
 587    def scaling_displayof(win, scale=nil)
 588      if scale
 589        tk_call('tk', 'scaling', '-displayof', win, scale)
 590      else
 591        Float(number(tk_call('tk', '-displayof', win, 'scaling')))
 592      end
 593    end
 594  
 595    def appname(name=None)
 596      tk_call('tk', 'appname', name)
 597    end
 598  
 599    def appsend(interp, async, *args)
 600      if async
 601        tk_call('send', '-async', '--', interp, *args)
 602      else
 603        tk_call('send', '--', interp, *args)
 604      end
 605    end
 606  
 607    def rb_appsend(interp, async, *args)
 608      args = args.collect!{|c| _get_eval_string(c).gsub(/[][$"]/, '\\\\\&')}
 609      args.push(').to_s"')
 610      appsend(interp, async, 'ruby "(', *args)
 611    end
 612  
 613    def appsend_displayof(interp, win, async, *args)
 614      win = '.' if win == nil
 615      if async
 616        tk_call('send', '-async', '-displayof', win, '--', interp, *args)
 617      else
 618        tk_call('send', '-displayor', win, '--', interp, *args)
 619      end
 620    end
 621  
 622    def rb_appsend_displayof(interp, win, async, *args)
 623      args = args.collect!{|c| _get_eval_string(c).gsub(/[][$"]/, '\\\\\&')}
 624      args.push(').to_s"')
 625      appsend_displayof(interp, win, async, 'ruby "(', *args)
 626    end
 627  
 628    def info(*args)
 629      tk_call('info', *args)
 630    end
 631  
 632    def mainloop(check_root = true)
 633      TclTkLib.mainloop(check_root)
 634    end
 635  
 636    def mainloop_watchdog(check_root = true)
 637      TclTkLib.mainloop_watchdog(check_root)
 638    end
 639  
 640    def do_one_event(flag = 0)
 641      TclTkLib.do_one_event(flag)
 642    end
 643  
 644    def set_eventloop_tick(timer_tick)
 645      TclTkLib.set_eventloop_tick(timer_tick)
 646    end
 647  
 648    def get_eventloop_tick()
 649      TclTkLib.get_eventloop_tick
 650    end
 651  
 652    def set_eventloop_weight(loop_max, no_event_tick)
 653      TclTkLib.set_eventloop_weight(loop_max, no_event_tick)
 654    end
 655  
 656    def get_eventloop_weight()
 657      TclTkLib.get_eventloop_weight
 658    end
 659  
 660    def restart(app_name = nil, use = nil)
 661      tk_call('set', 'argv0', app_name) if app_name
 662      if use
 663        tk_call('set', 'argc', 2)
 664        tk_call('set', 'argv', "-use #{use}")
 665      end
 666      TkCore::INTERP.restart
 667      TkComm::Tk_CMDTBL.clear
 668      TkComm::Tk_WINDOWS.clear
 669      nil
 670    end
 671  
 672    def event_generate(window, context, keys=nil)
 673      window = window.path if window.kind_of? TkObject
 674      if keys
 675        tk_call('event', 'generate', window, 
 676                "<#{tk_event_sequence(context)}>", *hash_kv(keys))
 677      else
 678        tk_call('event', 'generate', window, "<#{tk_event_sequence(context)}>")
 679      end
 680    end
 681  
 682    def messageBox(keys)
 683      tk_call 'tk_messageBox', *hash_kv(keys)
 684    end
 685  
 686    def getOpenFile(keys = nil)
 687      tk_call 'tk_getOpenFile', *hash_kv(keys)
 688    end
 689  
 690    def getSaveFile(keys = nil)
 691      tk_call 'tk_getSaveFile', *hash_kv(keys)
 692    end
 693  
 694    def chooseColor(keys = nil)
 695      tk_call 'tk_chooseColor', *hash_kv(keys)
 696    end
 697  
 698    def chooseDirectory(keys = nil)
 699      tk_call 'tk_chooseDirectory', *hash_kv(keys)
 700    end
 701  
 702    def tk_call(*args)
 703      puts args.inspect if $DEBUG
 704      args.collect! {|x|ruby2tcl(x)}
 705      args.compact!
 706      args.flatten!
 707      print "=> ", args.join(" ").inspect, "\n" if $DEBUG
 708      begin
 709        res = INTERP._invoke(*args)
 710      rescue NameError
 711        err = $!
 712        begin
 713          args.unshift "unknown"
 714          res = INTERP._invoke(*args)
 715        rescue
 716          fail unless /^invalid command/ =~ $!
 717          fail err
 718        end
 719      end
 720      if  INTERP._return_value() != 0
 721        fail RuntimeError, res, error_at
 722      end
 723      print "==> ", res.inspect, "\n" if $DEBUG
 724      return res
 725    end
 726  end
 727  
 728  module TkPackage
 729    include TkCore
 730    extend TkPackage
 731  
 732    def add_path(path)
 733      Tk::AUTO_PATH.value = Tk::AUTO_PATH.to_a << path
 734    end
 735  
 736    def forget(package)
 737      tk_call('package', 'forget', package)
 738      nil
 739    end
 740  
 741    def names
 742      tk_split_simplelist(tk_call('package', 'names'))
 743    end
 744  
 745    def provide(package, version=nil)
 746      if version
 747        tk_call('package', 'provide', package, version)
 748        nil
 749      else
 750        tk_call('package', 'provide', package)
 751      end
 752    end
 753  
 754    def present(package, version=None)
 755      tk_call('package', 'present', package, version)
 756    end
 757  
 758    def present_exact(package, version)
 759      tk_call('package', 'present', '-exact', package, version)
 760    end
 761  
 762    def require(package, version=None)
 763      tk_call('package', 'require', package, version)
 764    end
 765  
 766    def require_exact(package, version)
 767      tk_call('package', 'require', '-exact', package, version)
 768    end
 769  
 770    def versions(package)
 771      tk_split_simplelist(tk_call('package', 'versions', package))
 772    end
 773  
 774    def vcompare(version1, version2)
 775      Integer(tk_call('package', 'vcompare', version1, version2))
 776    end
 777  
 778    def vsatisfies(version1, version2)
 779      bool(tk_call('package', 'vsatisfies', version1, version2))
 780    end
 781  end
 782  
 783  module Tk
 784    include TkCore
 785    extend Tk
 786  
 787    TCL_VERSION = INTERP._invoke("info", "tclversion")
 788    TK_VERSION  = INTERP._invoke("set", "tk_version")
 789  
 790    TCL_PATCHLEVEL = INTERP._invoke("info", "patchlevel")
 791    TK_PATCHLEVEL  = INTERP._invoke("set", "tk_patchLevel")
 792  
 793    TCL_LIBRARY = INTERP._invoke("set", "tcl_library")
 794    TK_LIBRARY  = INTERP._invoke("set", "tk_library")
 795    LIBRARY     = INTERP._invoke("info", "library")
 796  
 797    PLATFORM = Hash[*tk_split_simplelist(INTERP._eval('array get tcl_platform'))]
 798  
 799    JAPANIZED_TK = (INTERP._invoke("info", "commands", "kanji") != "")
 800  
 801    def root
 802      TkRoot.new
 803    end
 804  
 805    def bell
 806      tk_call 'bell'
 807    end
 808  
 809    def Tk.focus(display=nil)
 810      if display == nil
 811        r = tk_call('focus')
 812      else
 813        r = tk_call('focus', '-displayof', display)
 814      end
 815      tk_tcl2ruby(r)
 816    end
 817  
 818    def Tk.focus_lastfor(win)
 819      tk_tcl2ruby(tk_call('focus', '-lastfor', win))
 820    end
 821  
 822    def Tk.strictMotif(bool=None)
 823      bool(tk_call('set', 'tk_strictMotif', bool))
 824    end
 825  
 826    def Tk.show_kinsoku(mode='both')
 827      begin
 828        if /^8\.*/ === TK_VERSION  && JAPANIZED_TK
 829          tk_split_simplelist(tk_call('kinsoku', 'show', mode))
 830        end
 831      rescue
 832      end
 833    end
 834    def Tk.add_kinsoku(chars, mode='both')
 835      begin
 836        if /^8\.*/ === TK_VERSION  && JAPANIZED_TK
 837          tk_split_simplelist(tk_call('kinsoku', 'add', mode, 
 838                                      *(chars.split(''))))
 839        else
 840          []
 841        end
 842      rescue
 843        []
 844      end
 845    end
 846    def Tk.delete_kinsoku(chars, mode='both')
 847      begin
 848        if /^8\.*/ === TK_VERSION  && JAPANIZED_TK
 849          tk_split_simplelist(tk_call('kinsoku', 'delete', mode, 
 850                              *(chars.split(''))))
 851        end
 852      rescue
 853      end
 854    end
 855  
 856    def Tk.toUTF8(str,encoding)
 857      INTERP._toUTF8(str,encoding)
 858    end
 859    
 860    def Tk.fromUTF8(str,encoding)
 861      INTERP._fromUTF8(str,encoding)
 862    end
 863  
 864    module Scrollable
 865      def xscrollcommand(cmd=Proc.new)
 866        configure_cmd 'xscrollcommand', cmd
 867      end
 868      def yscrollcommand(cmd=Proc.new)
 869        configure_cmd 'yscrollcommand', cmd
 870      end
 871      def xview(*index)
 872        v = tk_send('xview', *index)
 873        list(v) if index.size == 0
 874      end
 875      def yview(*index)
 876        v = tk_send('yview', *index)
 877        list(v) if index.size == 0
 878      end
 879      def xscrollbar(bar=nil)
 880        if bar
 881          @xscrollbar = bar
 882          @xscrollbar.orient 'horizontal'
 883          self.xscrollcommand {|arg| @xscrollbar.set(*arg)}
 884          @xscrollbar.command {|arg| self.xview(*arg)}
 885        end
 886        @xscrollbar
 887      end
 888      def yscrollbar(bar=nil)
 889        if bar
 890          @yscrollbar = bar
 891          @yscrollbar.orient 'vertical'
 892          self.yscrollcommand {|arg| @yscrollbar.set(*arg)}
 893          @yscrollbar.command {|arg| self.yview(*arg)}
 894        end
 895        @yscrollbar
 896      end
 897    end
 898  
 899    module Wm
 900      include TkComm
 901      def aspect(*args)
 902        w = tk_call('wm', 'aspect', path, *args)
 903        list(w) if args.length == 0
 904      end
 905      def client(name=None)
 906        tk_call 'wm', 'client', path, name
 907      end
 908      def colormapwindows(*args)
 909        list(tk_call('wm', 'colormapwindows', path, *args))
 910      end
 911      def wm_command(value=None)
 912        string(tk_call('wm', 'command', path, value))
 913      end
 914      def deiconify
 915        tk_call 'wm', 'deiconify', path
 916      end
 917      def focusmodel(*args)
 918        tk_call 'wm', 'focusmodel', path, *args
 919      end
 920      def frame
 921        tk_call('wm', 'frame', path)
 922      end
 923      def geometry(*args)
 924        tk_call('wm', 'geometry', path, *args)
 925      end
 926      def grid(*args)
 927        w = tk_call('wm', 'grid', path, *args)
 928        list(w) if args.size == 0
 929      end
 930      def group(*args)
 931        w = tk_call 'wm', 'group', path, *args
 932        window(w) if args.size == 0
 933      end
 934      def iconbitmap(*args)
 935        tk_call 'wm', 'iconbitmap', path, *args
 936      end
 937      def iconify
 938        tk_call 'wm', 'iconify', path
 939      end
 940      def iconmask(*args)
 941        tk_call 'wm', 'iconmask', path, *args
 942      end
 943      def iconname(*args)
 944        tk_call 'wm', 'iconname', path, *args
 945      end
 946      def iconposition(*args)
 947        w = tk_call('wm', 'iconposition', path, *args)
 948        list(w) if args.size == 0
 949      end
 950      def iconwindow(*args)
 951        w = tk_call('wm', 'iconwindow', path, *args)
 952        window(w) if args.size == 0
 953      end
 954      def maxsize(*args)
 955        w = tk_call('wm', 'maxsize', path, *args)
 956        list(w) if args.size == 0
 957      end
 958      def minsize(*args)
 959        w = tk_call('wm', 'minsize', path, *args)
 960        list(w) if args.size == 0
 961      end
 962      def overrideredirect(bool=None)
 963        if bool == None
 964          bool(tk_call('wm', 'overrideredirect', path))
 965        else
 966          tk_call 'wm', 'overrideredirect', path, bool
 967        end
 968      end
 969      def positionfrom(*args)
 970        tk_call 'wm', 'positionfrom', path, *args
 971      end
 972      def protocol(name=nil, cmd=nil)
 973        if cmd
 974          tk_call('wm', 'protocol', path, name, cmd)
 975        elsif name
 976          result = tk_call('wm', 'protocol', path, name)
 977          (result == "")? nil : tk_tcl2ruby(result)
 978        else
 979          tk_split_simplelist(tk_call('wm', 'protocol', path))
 980        end
 981      end
 982      def resizable(*args)
 983        w = tk_call('wm', 'resizable', path, *args)
 984        if args.length == 0
 985          list(w).collect{|e| bool(e)}
 986        end
 987      end
 988      def sizefrom(*args)
 989        tk_call('wm', 'sizefrom', path, *args)
 990      end
 991      def state(state=None)
 992        tk_call 'wm', 'state', path, state
 993      end
 994      def title(*args)
 995        tk_call 'wm', 'title', path, *args
 996      end
 997      def transient(*args)
 998        window(tk_call('wm', 'transient', path, *args))
 999      end
1000      def withdraw
1001        tk_call 'wm', 'withdraw', path
1002      end
1003    end
1004  end
1005  
1006  ###########################################
1007  #  convert kanji string to/from utf-8
1008  ###########################################
1009  if /^8\.[1-9]/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK
1010    class TclTkIp
1011      # from tkencoding.rb by ttate@jaist.ac.jp
1012      alias __eval _eval
1013      alias __invoke _invoke
1014      private :__eval
1015      private :__invoke
1016      
1017      attr_accessor :encoding
1018      
1019      def _eval(cmd)
1020        if @encoding
1021          _fromUTF8(__eval(_toUTF8(cmd, @encoding)), @encoding)
1022        else
1023          __eval(cmd)
1024        end
1025      end
1026      
1027      def _invoke(*cmds)
1028        if @encoding
1029          cmds = cmds.collect{|cmd| _toUTF8(cmd, @encoding)}
1030          _fromUTF8(__invoke(*cmds), @encoding)
1031        else
1032          __invoke(*cmds)
1033          end
1034      end
1035    end
1036  
1037    module Tk
1038      def encoding=(name)
1039        INTERP.encoding = name
1040      end
1041  
1042      def encoding
1043        INTERP.encoding
1044      end
1045  
1046      def encoding_names
1047        tk_split_simplelist(tk_call('encoding', 'names'))
1048      end
1049  
1050      def encoding_system
1051        tk_call('encoding', 'system')
1052      end
1053  
1054      def encoding_system=(enc)
1055        tk_call('encoding', 'system', enc)
1056      end
1057    end
1058  
1059    # estimate encoding
1060    case $KCODE
1061    when /^e/i  # EUC
1062      Tk.encoding = 'euc-jp'
1063    when /^s/i  # SJIS
1064      Tk.encoding = 'shiftjis'
1065    when /^u/i  # UTF8
1066      Tk.encoding = 'utf-8'
1067    else        # NONE
1068      begin
1069        Tk.encoding = Tk.encoding_system
1070      rescue StandardError, NameError
1071        Tk.encoding = 'utf-8'
1072      end
1073    end
1074  
1075  else
1076    # dummy methods
1077    module Tk
1078      def encoding=(name)
1079        nil
1080      end
1081      def encoding
1082        nil
1083      end
1084      def encoding_names
1085        nil
1086      end
1087      def encoding_system
1088        nil
1089      end
1090      def encoding_system=(enc)
1091        nil
1092      end
1093    end
1094  end
1095  
1096  module TkBindCore
1097    def bind(context, cmd=Proc.new, args=nil)
1098      Tk.bind(to_eval, context, cmd, args)
1099    end
1100  
1101    def bind_append(context, cmd=Proc.new, args=nil)
1102      Tk.bind_append(to_eval, context, cmd, args)
1103    end
1104  
1105    def bind_remove(context)
1106      Tk.bind_remove(to_eval, context)
1107    end
1108  
1109    def bindinfo(context=nil)
1110      Tk.bindinfo(to_eval, context)
1111    end
1112  end
1113  
1114  class TkBindTag
1115    include TkBindCore
1116  
1117    BTagID_TBL = {}
1118    Tk_BINDTAG_ID = ["btag00000"]
1119  
1120    def TkBindTag.id2obj(id)
1121      BTagID_TBL[id]? BTagID_TBL[id]: id
1122    end
1123  
1124    ALL = self.new
1125    ALL.instance_eval {
1126      @id = 'all'
1127      BTagID_TBL[@id] = self
1128    }
1129  
1130    def initialize(*args)
1131      @id = Tk_BINDTAG_ID[0]
1132      Tk_BINDTAG_ID[0] = Tk_BINDTAG_ID[0].succ
1133      BTagID_TBL[@id] = self
1134      bind(*args) if args != []
1135    end
1136  
1137    def to_eval
1138      @id
1139    end
1140  
1141    def inspect
1142      format "#<TkBindTag: %s>", @id
1143    end
1144  end
1145  
1146  class TkBindTagAll<TkBindTag
1147    def TkBindTagAll.new(*args)
1148      $stderr.puts "Warning: TkBindTagALL is obsolete. Use TkBindTag::ALL\n"
1149  
1150      TkBindTag::ALL.bind(*args) if args != []
1151      TkBindTag::ALL
1152    end
1153  end
1154  
1155  class TkVariable
1156    include Tk
1157    extend TkCore
1158  
1159    TkVar_CB_TBL = {}
1160    Tk_VARIABLE_ID = ["v00000"]
1161  
1162    INTERP._invoke("proc", "rb_var", "args", "ruby [format \"TkVariable.callback %%Q!%s!\" $args]")
1163  
1164    def TkVariable.callback(args)
1165      name1,name2,op = tk_split_list(args)
1166      if TkVar_CB_TBL[name1]
1167        _get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op))
1168      else
1169        ''
1170      end
1171    end
1172  
1173    def initialize(val="")
1174      @id = Tk_VARIABLE_ID[0]
1175      Tk_VARIABLE_ID[0] = Tk_VARIABLE_ID[0].succ
1176      if val == []
1177        INTERP._eval(format('global %s; set %s(0) 0; unset %s(0)', 
1178                            @id, @id, @id))
1179      elsif val.kind_of?(Array)
1180        a = []
1181        val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))}
1182        s = '"' + a.join(" ").gsub(/[][$"]/, '\\\\\&') + '"'
1183        INTERP._eval(format('global %s; array set %s %s', @id, @id, s))
1184      elsif  val.kind_of?(Hash)
1185        s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\
1186                     .gsub(/[][$"]/, '\\\\\&') + '"'
1187        INTERP._eval(format('global %s; array set %s %s', @id, @id, s))
1188      else
1189        s = '"' + _get_eval_string(val).gsub(/[][$"]/, '\\\\\&') + '"'
1190        INTERP._eval(format('global %s; set %s %s', @id, @id, s))
1191      end
1192    end
1193  
1194    def wait
1195      INTERP._eval("tkwait variable #{@id}")
1196    end
1197  
1198    def id
1199      @id
1200    end
1201  
1202    def value
1203      begin
1204        INTERP._eval(format('global %s; set %s', @id, @id))
1205      rescue
1206        if INTERP._eval(format('global %s; array exists %s', @id, @id)) != "1"
1207          fail
1208        else
1209          Hash[*tk_split_simplelist(INTERP._eval(format('global %s; array get %s', 
1210                                                        @id, @id)))]
1211        end
1212      end
1213    end
1214  
1215    def value=(val)
1216      begin
1217        s = '"' + _get_eval_string(val).gsub(/[][$"]/, '\\\\\&') + '"'
1218        INTERP._eval(format('global %s; set %s %s', @id, @id, s))
1219      rescue
1220        if INTERP._eval(format('global %s; array exists %s', @id, @id)) != "1"
1221          fail
1222        else
1223          if val == []
1224            INTERP._eval(format('global %s; unset %s; set %s(0) 0; unset %s(0)', 
1225                                @id, @id, @id, @id))
1226          elsif val.kind_of?(Array)
1227            a = []
1228            val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))}
1229            s = '"' + a.join(" ").gsub(/[][$"]/, '\\\\\&') + '"'
1230            INTERP._eval(format('global %s; unset %s; array set %s %s', 
1231                                @id, @id, @id, s))
1232          elsif  val.kind_of?(Hash)
1233            s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\
1234                                  .gsub(/[][$"]/, '\\\\\&') + '"'
1235            INTERP._eval(format('global %s; unset %s; array set %s %s', 
1236                                @id, @id, @id, s))
1237          else
1238            fail
1239          end
1240        end
1241      end
1242    end
1243  
1244    def [](index)
1245      INTERP._eval(format('global %s; set %s(%s)', 
1246                          @id, @id, _get_eval_string(index)))
1247    end
1248  
1249    def []=(index,val)
1250      INTERP._eval(format('global %s; set %s(%s) %s', @id, @id, 
1251                          _get_eval_string(index), _get_eval_string(val)))
1252    end
1253  
1254    def to_i
1255      number(value).to_i
1256    end
1257  
1258    def to_f
1259      number(value).to_f
1260    end
1261  
1262    def to_s
1263      string(value).to_s
1264    end
1265  
1266    def inspect
1267      format "#<TkVariable: %s>", @id
1268    end
1269  
1270    def ==(other)
1271      case other
1272      when TkVariable
1273        self.equal(self)
1274      when String
1275        self.to_s == other
1276      when Integer
1277        self.to_i == other
1278      when Float
1279        self.to_f == other
1280      when Array
1281        self.to_a == other
1282      else
1283        false
1284      end
1285    end
1286  
1287    def to_a
1288      list(value)
1289    end
1290  
1291    def to_eval
1292      @id
1293    end
1294  
1295    def unset(elem=nil)
1296      if elem
1297        INTERP._eval(format('global %s; unset %s(%s)', 
1298                            @id, @id, tk_tcl2ruby(elem)))
1299      else
1300        INTERP._eval(format('global %s; unset %s', @id, @id))
1301      end
1302    end
1303    alias remove unset
1304  
1305    def trace_callback(elem, op)
1306      if @trace_var.kind_of? Array
1307        @trace_var.each{|m,e| e.call(self,elem,op) if m.index(op)}
1308      end
1309      if elem.kind_of? String
1310        if @trace_elem[elem].kind_of? Array
1311          @trace_elem[elem].each{|m,e| e.call(self,elem,op) if m.index(op)}
1312        end
1313      end
1314    end
1315  
1316    def trace(opts, cmd)
1317      @trace_var = [] if @trace_var == nil
1318      opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
1319      @trace_var.unshift([opts,cmd])
1320      if @trace_opts == nil
1321        TkVar_CB_TBL[@id] = self
1322        @trace_opts = opts
1323        Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
1324      else
1325        newopts = @trace_opts.dup
1326        opts.each_byte{|c| newopts += c.chr unless newopts.index(c)}
1327        if newopts != @trace_opts
1328          Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var')
1329          @trace_opts.replace(newopts)
1330          Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
1331        end
1332      end
1333    end
1334  
1335    def trace_element(elem, opts, cmd)
1336      @trace_elem = {} if @trace_elem == nil
1337      @trace_elem[elem] = [] if @trace_elem[elem] == nil
1338      opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
1339      @trace_elem[elem].unshift([opts,cmd])
1340      if @trace_opts == nil
1341        TkVar_CB_TBL[@id] = self
1342        @trace_opts = opts
1343        Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
1344      else
1345        newopts = @trace_opts.dup
1346        opts.each_byte{|c| newopts += c.chr unless newopts.index(c)}
1347        if newopts != @trace_opts
1348          Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var')
1349          @trace_opts.replace(newopts)
1350          Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
1351        end
1352      end
1353    end
1354  
1355    def trace_vinfo
1356      return [] unless @trace_var
1357      @trace_var.dup
1358    end
1359    def trace_vinfo_for_element(elem)
1360      return [] unless @trace_elem
1361      return [] unless @trace_elem[elem]
1362      @trace_elem[elem].dup
1363    end
1364  
1365    def trace_vdelete(opts,cmd)
1366      return unless @trace_var.kind_of? Array
1367      opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
1368      idx = -1
1369      newopts = ''
1370      @trace_var.each_with_index{|e,i| 
1371        if idx < 0 && e[0] == opts && e[1] == cmd
1372          idx = i
1373          next
1374        end
1375        e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
1376      }
1377      if idx >= 0
1378        @trace_var.delete_at(idx) 
1379      else
1380        return
1381      end
1382  
1383      @trace_elem.each{|elem|
1384        @trace_elem[elem].each{|e|
1385          e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
1386        }
1387      }
1388  
1389      newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('')
1390      if newopts != @trace_opts
1391        Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var')
1392        @trace_opts.replace(newopts)
1393        if @trace_opts != ''
1394          Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
1395        end
1396      end
1397    end
1398  
1399    def trace_vdelete_for_element(elem,opts,cmd)
1400      return unless @trace_elem.kind_of? Hash
1401      return unless @trace_elem[elem].kind_of? Array
1402      opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
1403      idx = -1
1404      @trace_elem[elem].each_with_index{|e,i| 
1405        if idx < 0 && e[0] == opts && e[1] == cmd
1406          idx = i
1407          next
1408        end
1409      }
1410      if idx >= 0
1411        @trace_elem[elem].delete_at(idx)
1412      else
1413        return
1414      end
1415  
1416      newopts = ''
1417      @trace_var.each{|e| 
1418        e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
1419      }
1420      @trace_elem.each{|elem|
1421        @trace_elem[elem].each{|e|
1422          e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
1423        }
1424      }
1425  
1426      newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('')
1427      if newopts != @trace_opts
1428        Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var')
1429        @trace_opts.replace(newopts)
1430        if @trace_opts != ''
1431          Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
1432        end
1433      end
1434    end
1435  end
1436  
1437  class TkVarAccess<TkVariable
1438    def initialize(varname, val=nil)
1439      @id = varname
1440      if val
1441        s = '"' + _get_eval_string(val).gsub(/[][$"]/, '\\\\\&') + '"' #"
1442        INTERP._eval(format('global %s; set %s %s', @id, @id, s))
1443      end
1444    end
1445  end
1446  
1447  module Tk
1448    begin
1449      auto_path = INTERP._invoke('set', 'auto_path')
1450    rescue
1451      begin
1452        auto_path = INTERP._invoke('set', 'env(TCLLIBPATH)')
1453      rescue
1454        auto_path = Tk::LIBRARY
1455      end
1456    end
1457    AUTO_PATH = TkVarAccess.new('auto_path', auto_path)
1458  
1459    TCL_PACKAGE_PATH = TkVarAccess.new('tcl_pkgPath')
1460  end
1461  
1462  module TkSelection
1463    include Tk
1464    extend Tk
1465    def clear(win=Tk.root)
1466      tk_call 'selection', 'clear', win.path
1467    end
1468    def get(type=None)
1469      tk_call 'selection', 'get', type
1470    end
1471    def TkSelection.handle(win, func, type=None, format=None)
1472      tk_call 'selection', 'handle', win.path, func, type, format
1473    end
1474    def handle(func, type=None, format=None)
1475      TkSelection.handle self, func, type, format
1476    end
1477    def TkSelection.own(win=None, func=None)
1478      window(tk_call('selection', 'own', win, func))
1479    end
1480    def own(func=None)
1481      TkSelection.own self, func
1482    end
1483  
1484    module_function :clear, :get
1485  end
1486  
1487  module TkKinput
1488    include Tk
1489    extend Tk
1490  
1491    def TkKinput.start(window, style=None)
1492      tk_call 'kinput_start', window.path, style
1493    end
1494    def kinput_start(style=None)
1495      TkKinput.start(self, style)
1496    end
1497  
1498    def TkKinput.send_spot(window)
1499      tk_call 'kinput_send_spot', window.path
1500    end
1501    def kinput_send_spot
1502      TkKinput.send_spot(self)
1503    end
1504  
1505    def TkKinput.input_start(window, keys=nil)
1506      tk_call 'kanjiInput', 'start', window.path, *hash_kv(keys)
1507    end
1508    def kanji_input_start(keys=nil)
1509      TkKinput.input_start(self, keys)
1510    end
1511  
1512    def TkKinput.attribute_config(window, slot, value=None)
1513      if slot.kind_of? Hash
1514        tk_call 'kanjiInput', 'attribute', window.path, *hash_kv(slot)
1515      else
1516        tk_call 'kanjiInput', 'attribute', window.path, "-#{slot}", value
1517      end
1518    end
1519    def kinput_attribute_config(slot, value=None)
1520      TkKinput.attribute_config(self, slot, value)
1521    end
1522  
1523    def TkKinput.attribute_info(window, slot=nil)
1524      if slot
1525        conf = tk_split_list(tk_call('kanjiInput', 'attribute', 
1526                                     window.path, "-#{slot}"))
1527        conf[0] = conf[0][1..-1]
1528        conf
1529      else
1530        tk_split_list(tk_call('kanjiInput', 'attribute', 
1531                              window.path)).collect{|conf|
1532          conf[0] = conf[0][1..-1]
1533          conf
1534        }
1535      end
1536    end
1537    def kinput_attribute_info(slot=nil)
1538      TkKinput.attribute_info(self, slot)
1539    end
1540  
1541    def TkKinput.input_end(window)
1542      tk_call 'kanjiInput', 'end', window.path
1543    end
1544    def kanji_input_end
1545      TkKinput.input_end(self)
1546    end
1547  end
1548  
1549  module TkXIM
1550    include Tk
1551    extend Tk
1552  
1553    def TkXIM.useinputmethods(window=nil, value=nil)
1554      if window
1555        if value
1556          tk_call 'tk', 'useinputmethods', '-displayof', window.path, value
1557        else
1558          tk_call 'tk', 'useinputmethods', '-displayof', window.path
1559        end
1560      else
1561        if value
1562          tk_call 'tk', 'useinputmethods', value
1563        else
1564          tk_call 'tk', 'useinputmethods'
1565        end
1566      end
1567    end
1568  
1569    def TkXIM.configure(window, slot, value=None)
1570      begin
1571        if /^8\.*/ === Tk::TK_VERSION  && JAPANIZED_TK
1572          if slot.kind_of? Hash
1573            tk_call 'imconfigure', window.path, *hash_kv(slot)
1574          else
1575            tk_call 'imconfigure', window.path, "-#{slot}", value
1576          end
1577        end
1578      rescue
1579      end
1580    end
1581  
1582    def TkXIM.configinfo(window, slot=nil)
1583      begin
1584        if /^8\.*/ === Tk::TK_VERSION  && JAPANIZED_TK
1585          if slot
1586            conf = tk_split_list(tk_call('imconfigure', window.path, "-#{slot}"))
1587            conf[0] = conf[0][1..-1]
1588            conf
1589          else
1590            tk_split_list(tk_call('imconfigure', window.path)).collect{|conf|
1591              conf[0] = conf[0][1..-1]
1592              conf
1593            }
1594          end
1595        else
1596          []
1597        end
1598      rescue
1599        []
1600      end
1601    end
1602  
1603    def useinputmethods(value=nil)
1604      TkXIM.useinputmethods(self, value)
1605    end
1606  
1607    def imconfigure(window, slot, value=None)
1608      TkXIM.configinfo(window, slot, value)
1609    end
1610  
1611    def imconfiginfo(slot=nil)
1612      TkXIM.configinfo(window, slot)
1613    end
1614  end
1615  
1616  module TkWinfo
1617    include Tk
1618    extend Tk
1619    def TkWinfo.atom(name)
1620      number(tk_call('winfo', 'atom', name))
1621    end
1622    def winfo_atom(name)
1623      TkWinfo.atom name
1624    end
1625    def TkWinfo.atomname(id)
1626      tk_call 'winfo', 'atomname', id
1627    end
1628    def winfo_atomname(id)
1629      TkWinfo.atomname id
1630    end
1631    def TkWinfo.cells(window)
1632      number(tk_call('winfo', 'cells', window.path))
1633    end
1634    def winfo_cells
1635      TkWinfo.cells self
1636    end
1637    def TkWinfo.children(window)
1638      c = tk_call('winfo', 'children', window.path)
1639      list(c)
1640    end
1641    def winfo_children
1642      TkWinfo.children self
1643    end
1644    def TkWinfo.classname(window)
1645      tk_call 'winfo', 'class', window.path
1646    end
1647    def winfo_classname
1648      TkWinfo.classname self
1649    end
1650    def TkWinfo.colormapfull(window)
1651       bool(tk_call('winfo', 'colormapfull', window.path))
1652    end
1653    def winfo_colormapfull
1654      TkWinfo.colormapfull self
1655    end
1656    def TkWinfo.containing(rootX, rootY)
1657      path = tk_call('winfo', 'containing', rootX, rootY)
1658      window(path)
1659    end
1660    def winfo_containing(x, y)
1661      TkWinfo.containing x, y
1662    end
1663    def TkWinfo.depth(window)
1664      number(tk_call('winfo', 'depth', window.path))
1665    end
1666    def winfo_depth
1667      TkWinfo.depth self
1668    end
1669    def TkWinfo.exist?(window)
1670      bool(tk_call('winfo', 'exists', window.path))
1671    end
1672    def winfo_exist?
1673      TkWinfo.exist? self
1674    end
1675    def TkWinfo.fpixels(window, number)
1676      number(tk_call('winfo', 'fpixels', window.path, number))
1677    end
1678    def winfo_fpixels(number)
1679      TkWinfo.fpixels self, number
1680    end
1681    def TkWinfo.geometry(window)
1682      tk_call('winfo', 'geometry', window.path)
1683    end
1684    def winfo_geometry
1685      TkWinfo.geometry self
1686    end
1687    def TkWinfo.height(window)
1688      number(tk_call('winfo', 'height', window.path))
1689    end
1690    def winfo_height
1691      TkWinfo.height self
1692    end
1693    def TkWinfo.id(window)
1694      tk_call('winfo', 'id', window.path)
1695    end
1696    def winfo_id
1697      TkWinfo.id self
1698    end
1699    def TkWinfo.interps(window=nil)
1700      if window
1701        tk_split_simplelist(tk_call('winfo', 'interps',
1702                                    '-displayof', window.path))
1703      else
1704        tk_split_simplelist(tk_call('winfo', 'interps'))
1705      end
1706    end
1707    def winfo_interps
1708      TkWinfo.interps self
1709    end
1710    def TkWinfo.mapped?(window)
1711      bool(tk_call('winfo', 'ismapped', window.path))
1712    end
1713    def winfo_mapped?
1714      TkWinfo.mapped? self
1715    end
1716    def TkWinfo.manager(window)
1717      tk_call('winfo', 'manager', window.path)
1718    end
1719    def winfo_manager
1720      TkWinfo.manager self
1721    end
1722    def TkWinfo.appname(window)
1723      tk_call('winfo', 'name', window.path)
1724    end
1725    def winfo_appname
1726      TkWinfo.appname self
1727    end
1728    def TkWinfo.parent(window)
1729      window(tk_call('winfo', 'parent', window.path))
1730    end
1731    def winfo_parent
1732      TkWinfo.parent self
1733    end
1734    def TkWinfo.widget(id)
1735      window(tk_call('winfo', 'pathname', id))
1736    end
1737    def winfo_widget(id)
1738      TkWinfo.widget id
1739    end
1740    def TkWinfo.pixels(window, number)
1741      number(tk_call('winfo', 'pixels', window.path, number))
1742    end
1743    def winfo_pixels(number)
1744      TkWinfo.pixels self, number
1745    end
1746    def TkWinfo.reqheight(window)
1747      number(tk_call('winfo', 'reqheight', window.path))
1748    end
1749    def winfo_reqheight
1750      TkWinfo.reqheight self
1751    end
1752    def TkWinfo.reqwidth(window)
1753      number(tk_call('winfo', 'reqwidth', window.path))
1754    end
1755    def winfo_reqwidth
1756      TkWinfo.reqwidth self
1757    end
1758    def TkWinfo.rgb(window, color)
1759      list(tk_call('winfo', 'rgb', window.path, color))
1760    end
1761    def winfo_rgb(color)
1762      TkWinfo.rgb self, color
1763    end
1764    def TkWinfo.rootx(window)
1765      number(tk_call('winfo', 'rootx', window.path))
1766    end
1767    def winfo_rootx
1768      TkWinfo.rootx self
1769    end
1770    def TkWinfo.rooty(window)
1771      number(tk_call('winfo', 'rooty', window.path))
1772    end
1773    def winfo_rooty
1774      TkWinfo.rooty self
1775    end
1776    def TkWinfo.screen(window)
1777      tk_call 'winfo', 'screen', window.path
1778    end
1779    def winfo_screen
1780      TkWinfo.screen self
1781    end
1782    def TkWinfo.screencells(window)
1783      number(tk_call('winfo', 'screencells', window.path))
1784    end
1785    def winfo_screencells
1786      TkWinfo.screencells self
1787    end
1788    def TkWinfo.screendepth(window)
1789      number(tk_call('winfo', 'screendepth', window.path))
1790    end
1791    def winfo_screendepth
1792      TkWinfo.screendepth self
1793    end
1794    def TkWinfo.screenheight (window)
1795      number(tk_call('winfo', 'screenheight', window.path))
1796    end
1797    def winfo_screenheight
1798      TkWinfo.screenheight self
1799    end
1800    def TkWinfo.screenmmheight(window)
1801      number(tk_call('winfo', 'screenmmheight', window.path))
1802    end
1803    def winfo_screenmmheight
1804      TkWinfo.screenmmheight self
1805    end
1806    def TkWinfo.screenmmwidth(window)
1807      number(tk_call('winfo', 'screenmmwidth', window.path))
1808    end
1809    def winfo_screenmmwidth
1810      TkWinfo.screenmmwidth self
1811    end
1812    def TkWinfo.screenvisual(window)
1813      tk_call 'winfo', 'screenvisual', window.path
1814    end
1815    def winfo_screenvisual
1816      TkWinfo.screenvisual self
1817    end
1818    def TkWinfo.screenwidth(window)
1819      number(tk_call('winfo', 'screenwidth', window.path))
1820    end
1821    def winfo_screenwidth
1822      TkWinfo.screenwidth self
1823    end
1824    def TkWinfo.server(window)
1825      tk_call 'winfo', 'server', window.path
1826    end
1827    def winfo_server
1828      TkWinfo.server self
1829    end
1830    def TkWinfo.toplevel(window)
1831      window(tk_call('winfo', 'toplevel', window.path))
1832    end
1833    def winfo_toplevel
1834      TkWinfo.toplevel self
1835    end
1836    def TkWinfo.visual(window)
1837      tk_call 'winfo', 'visual', window.path
1838    end
1839    def winfo_visual
1840      TkWinfo.visual self
1841    end
1842    def TkWinfo.visualid(window)
1843      tk_call 'winfo', 'visualid', window.path
1844    end
1845    def winfo_visualid
1846      TkWinfo.visualid self
1847    end
1848    def TkWinfo.visualsavailable(window, includeids=false)
1849      if includeids
1850        v = tk_call('winfo', 'visualsavailable', window.path, "includeids")
1851      else
1852        v = tk_call('winfo', 'visualsavailable', window.path)
1853      end
1854      list(v)
1855    end
1856    def winfo_visualsavailable(includeids=false)
1857      TkWinfo.visualsavailable self, includeids
1858    end
1859    def TkWinfo.vrootheight(window)
1860      number(tk_call('winfo', 'vrootheight', window.path))
1861    end
1862    def winfo_vrootheight
1863      TkWinfo.vrootheight self
1864    end
1865    def TkWinfo.vrootwidth(window)
1866      number(tk_call('winfo', 'vrootwidth', window.path))
1867    end
1868    def winfo_vrootwidth
1869      TkWinfo.vrootwidth self
1870    end
1871    def TkWinfo.vrootx(window)
1872      number(tk_call('winfo', 'vrootx', window.path))
1873    end
1874    def winfo_vrootx
1875      TkWinfo.vrootx self
1876    end
1877    def TkWinfo.vrooty(window)
1878      number(tk_call('winfo', 'vrooty', window.path))
1879    end
1880    def winfo_vrooty
1881      TkWinfo.vrooty self
1882    end
1883    def TkWinfo.width(window)
1884      number(tk_call('winfo', 'width', window.path))
1885    end
1886    def winfo_width
1887      TkWinfo.width self
1888    end
1889    def TkWinfo.x(window)
1890      number(tk_call('winfo', 'x', window.path))
1891    end
1892    def winfo_x
1893      TkWinfo.x self
1894    end
1895    def TkWinfo.y(window)
1896      number(tk_call('winfo', 'y', window.path))
1897    end
1898    def winfo_y
1899      TkWinfo.y self
1900    end
1901    def TkWinfo.viewable(window)
1902      bool(tk_call('winfo', 'viewable', window.path))
1903    end
1904    def winfo_viewable
1905      TkWinfo.viewable self
1906    end
1907    def TkWinfo.pointerx(window)
1908      number(tk_call('winfo', 'pointerx', window.path))
1909    end
1910    def winfo_pointerx
1911      TkWinfo.pointerx self
1912    end
1913    def TkWinfo.pointery(window)
1914      number(tk_call('winfo', 'pointery', window.path))
1915    end
1916    def winfo_pointery
1917      TkWinfo.pointery self
1918    end
1919    def TkWinfo.pointerxy(window)
1920      list(tk_call('winfo', 'pointerxy', window.path))
1921    end
1922    def winfo_pointerxy
1923      TkWinfo.pointerxy self
1924    end
1925  end
1926  
1927  module TkPack
1928    include Tk
1929    extend Tk
1930    def configure(win, *args)
1931      if args[-1].kind_of?(Hash)
1932        keys = args.pop
1933      end
1934      wins = [win.epath]
1935      for i in args
1936        wins.push i.epath
1937      end
1938      tk_call "pack", 'configure', *(wins+hash_kv(keys))
1939    end
1940  
1941    def forget(*args)
1942      tk_call 'pack', 'forget' *args
1943    end
1944  
1945    def info(slave)
1946      ilist = list(tk_call('pack', 'info', slave.epath))
1947      info = {}
1948      while key = ilist.shift
1949        info[key[1..-1]] = ilist.shift
1950      end
1951      return info
1952    end
1953  
1954    def propagate(master, bool=None)
1955      if bool == None
1956        bool(tk_call('pack', 'propagate', master.epath))
1957      else
1958        tk_call('pack', 'propagate', master.epath, bool)
1959      end
1960    end
1961  
1962    def slaves(master)
1963      list(tk_call('pack', 'slaves', master.epath))
1964    end
1965  
1966    module_function :configure, :forget, :info, :propagate, :slaves
1967  end
1968  
1969  module TkGrid
1970    include Tk
1971    extend Tk
1972  
1973    def bbox(*args)
1974      list(tk_call('grid', 'bbox', *args))
1975    end
1976  
1977    def configure(widget, *args)
1978      if args[-1].kind_of?(Hash)
1979        keys = args.pop
1980      end
1981      wins = [widget.epath]
1982      for i in args
1983        wins.push i.epath
1984      end
1985      tk_call "grid", 'configure', *(wins+hash_kv(keys))
1986    end
1987  
1988    def columnconfigure(master, index, args)
1989      tk_call "grid", 'columnconfigure', master, index, *hash_kv(args)
1990    end
1991  
1992    def rowconfigure(master, index, args)
1993      tk_call "grid", 'rowconfigure', master, index, *hash_kv(args)
1994    end
1995  
1996    def columnconfiginfo(master, index, slot=nil)
1997      if slot
1998        tk_call 'grid', 'columnconfigure', master, index, "-#{slot}"
1999      else
2000        ilist = list(tk_call('grid', 'columnconfigure', master, index))
2001        info = {}
2002        while key = ilist.shift
2003          info[key[1..-1]] = ilist.shift
2004        end
2005        info
2006      end
2007    end
2008  
2009    def rowconfiginfo(master, index, slot=nil)
2010      if slot
2011        tk_call 'grid', 'rowconfigure', master, index, "-#{slot}"
2012      else
2013        ilist = list(tk_call('grid', 'rowconfigure', master, index))
2014        info = {}
2015        while key = ilist.shift
2016          info[key[1..-1]] = ilist.shift
2017        end
2018        info
2019      end
2020    end
2021  
2022    def add(widget, *args)
2023      configure(widget, *args)
2024    end
2025  
2026    def forget(*args)
2027      tk_call 'grid', 'forget', *args
2028    end
2029  
2030    def info(slave)
2031      list(tk_call('grid', 'info', slave))
2032    end
2033  
2034    def location(master, x, y)
2035      list(tk_call('grid', 'location', master, x, y))
2036    end
2037  
2038    def propagate(master, bool=None)
2039      if bool == None
2040        bool(tk_call('grid', 'propagate', master.epath))
2041      else
2042        tk_call('grid', 'propagate', master.epath, bool)
2043      end
2044    end
2045  
2046    def remove(*args)
2047      tk_call 'grid', 'remove', *args
2048    end
2049  
2050    def size(master)
2051      tk_call 'grid', 'size', master
2052    end
2053  
2054    def slaves(master, args)
2055      list(tk_call('grid', 'slaves', master, *hash_kv(args)))
2056    end
2057  
2058    module_function :bbox, :forget, :propagate, :info
2059    module_function :remove, :size, :slaves, :location
2060    module_function :configure, :columnconfigure, :rowconfigure
2061    module_function :columnconfiginfo, :rowconfiginfo
2062  end
2063  
2064  module TkPlace
2065    include Tk
2066    extend Tk
2067  
2068    def configure(win, slot, value=None)
2069      if slot.kind_of? Hash
2070        tk_call 'place', 'configure', win.epath, *hash_kv(slot)
2071      else
2072        tk_call 'place', 'configure', win.epath, "-#{slot}", value
2073      end
2074    end
2075  
2076    def configinfo(win, slot = nil)
2077      # for >= Tk8.4a2 ?
2078      if slot
2079        conf = tk_split_list(tk_call('place', 'configure', 
2080                                     win.epath, "-#{slot}") )
2081        conf[0] = conf[0][1..-1]
2082        conf
2083      else
2084        tk_split_simplelist(tk_call('place', 'configure', 
2085                                    win.epath)).collect{|conflist|
2086          conf = tk_split_simplelist(conflist)
2087          conf[0] = conf[0][1..-1]
2088          conf
2089        }
2090      end
2091    end
2092  
2093    def forget(win)
2094      tk_call 'place', 'forget', win
2095    end
2096  
2097    def info(win)
2098      ilist = list(tk_call('place', 'info', win.epath))
2099      info = {}
2100      while key = ilist.shift
2101        info[key[1..-1]] = ilist.shift
2102      end
2103      return info
2104    end
2105  
2106    def slaves(master)
2107      list(tk_call('place', 'slaves', master.epath))
2108    end
2109  
2110    module_function :configure, :configinfo, :forget, :info, :slaves
2111  end
2112  
2113  module TkOption
2114    include Tk
2115    extend Tk
2116    def add pat, value, pri=None
2117      tk_call 'option', 'add', pat, value, pri
2118    end
2119    def clear
2120      tk_call 'option', 'clear'
2121    end
2122    def get win, name, klass
2123      tk_call('option', 'get', win ,name, klass).taint
2124    end
2125    def readfile file, pri=None
2126      tk_call 'option', 'readfile', file, pri
2127    end
2128    module_function :add, :clear, :get, :readfile
2129  
2130    # support procs on the resource database
2131    @@resource_proc_class = Class.new
2132    class << @@resource_proc_class
2133      private :new
2134  
2135      CARRIER    = '.'.freeze
2136      METHOD_TBL = {}
2137      ADD_METHOD = false
2138      SAFE_MODE  = 4
2139  
2140      def __check_proc_string__(str)
2141        # If you want to check the proc_string, do it in this method.
2142        str
2143      end
2144  
2145      def method_missing(id, *args)
2146        res_proc = self::METHOD_TBL[id]
2147        unless res_proc.kind_of? Proc
2148          if id == :new || (!self::METHOD_TBL.has_key?(id) && !self::ADD_METHOD)
2149            raise NoMethodError, 
2150                  "not support resource-proc '#{id.id2name}' for #{self.name}"
2151          end
2152          proc_str = TkOption.get(self::CARRIER, id.id2name, '')
2153          proc_str = '{' + proc_str + '}' unless /\A\{.*\}\Z/ =~ proc_str
2154          proc_str = __check_proc_string__(proc_str)
2155          res_proc = eval 'Proc.new' + proc_str
2156          self::METHOD_TBL[id] = res_proc
2157        end
2158        proc{
2159           $SAFE = self::SAFE_MODE
2160           res_proc.call(*args)
2161        }.call
2162      end
2163  
2164      private :__check_proc_string__, :method_missing
2165    end
2166  
2167    def new_proc_class(klass, func, safe = 4, add = false, parent = nil)
2168      klass = klass.to_s if klass.kind_of? Symbol
2169      unless (?A..?Z) === klass[0]
2170        fail ArgumentError, "bad string '#{klass}' for class name"
2171      end
2172      unless func.kind_of? Array
2173        fail ArgumentError, "method-list must be Array"
2174      end
2175      func_str = func.join(' ')
2176      if parent == nil
2177        install_win(parent)
2178      elsif parent <= @@resource_proc_class
2179        install_win(parent::CARRIER)
2180      else
2181        fail ArgumentError, "parent must be Resource-Proc class"
2182      end
2183      carrier = Tk.tk_call('frame', @path, '-class', klass)
2184  
2185      body = <<-"EOD"
2186        class #{klass} < TkOption.module_eval('@@resource_proc_class')
2187          CARRIER    = '#{carrier}'.freeze
2188          METHOD_TBL = {}
2189          ADD_METHOD = #{add}
2190          SAFE_MODE  = #{safe}
2191          %w(#{func_str}).each{|f| METHOD_TBL[f.intern] = nil }
2192        end
2193      EOD
2194  
2195      if parent.kind_of?(Class) && parent <= @@resource_proc_class
2196        parent.class_eval body
2197        eval parent.name + '::' + klass
2198      else
2199        eval body
2200        eval 'TkOption::' + klass
2201      end
2202    end
2203    module_function :new_proc_class
2204  end
2205  
2206  module TkTreatFont
2207    def font_configinfo
2208      ret = TkFont.used_on(self.path)
2209      if ret == nil
2210        ret = TkFont.init_widget_font(self.path, self.path, 'configure')
2211      end
2212      ret
2213    end
2214    alias fontobj font_configinfo
2215  
2216    def font_configure(slot)
2217      slot = _symbolkey2str(slot)
2218      if (fnt = slot.delete('font'))
2219        if fnt.kind_of? TkFont
2220          return fnt.call_font_configure(self.path, self.path,'configure',slot)
2221        else
2222          latinfont_configure(fnt) if fnt
2223        end
2224      end
2225      if (ltn = slot.delete('latinfont'))
2226        latinfont_configure(ltn) if ltn
2227      end
2228      if (ltn = slot.delete('asciifont'))
2229        latinfont_configure(ltn) if ltn
2230      end
2231      if (knj = slot.delete('kanjifont'))
2232        kanjifont_configure(knj) if knj
2233      end
2234  
2235      tk_call(self.path, 'configure', *hash_kv(slot)) if slot != {}
2236      self
2237    end
2238  
2239    def latinfont_configure(ltn, keys=nil)
2240      fobj = fontobj
2241      if ltn.kind_of? TkFont
2242        conf = {}
2243        ltn.latin_configinfo.each{|key,val| conf[key] = val}
2244        if keys
2245          fobj.latin_configure(conf.update(keys))
2246        else
2247          fobj.latin_configure(conf)
2248        end
2249      else
2250        fobj.latin_replace(ltn)
2251      end
2252    end
2253    alias asciifont_configure latinfont_configure
2254  
2255    def kanjifont_configure(knj, keys=nil)
2256      fobj = fontobj
2257      if knj.kind_of? TkFont
2258        conf = {}
2259        knj.kanji_configinfo.each{|key,val| conf[key] = val}
2260        if keys
2261          fobj.kanji_configure(conf.update(keys))
2262        else
2263          fobj.kanji_configure(cond)
2264        end
2265      else
2266        fobj.kanji_replace(knj)
2267      end
2268    end
2269  
2270    def font_copy(window, tag=nil)
2271      if tag
2272        window.tagfontobj(tag).configinfo.each{|key,value|
2273          fontobj.configure(key,value)
2274        }
2275        fontobj.replace(window.tagfontobj(tag).latin_font, 
2276                        window.tagfontobj(tag).kanji_font)
2277      else
2278        window.fontobj.configinfo.each{|key,value|
2279          fontobj.configure(key,value)
2280        }
2281        fontobj.replace(window.fontobj.latin_font, window.fontobj.kanji_font)
2282      end
2283    end
2284  
2285    def latinfont_copy(window, tag=nil)
2286      if tag
2287        fontobj.latin_replace(window.tagfontobj(tag).latin_font)
2288      else
2289        fontobj.latin_replace(window.fontobj.latin_font)
2290      end
2291    end
2292    alias asciifont_copy latinfont_copy
2293  
2294    def kanjifont_copy(window, tag=nil)
2295      if tag
2296        fontobj.kanji_replace(window.tagfontobj(tag).kanji_font)
2297      else
2298        fontobj.kanji_replace(window.fontobj.kanji_font)
2299      end
2300    end
2301  end
2302  
2303  module TkTreatItemFont
2304    def __conf_cmd(idx)
2305      raise NotImplementError, "need to define `__conf_cmd'"
2306    end
2307    def __item_pathname(tagOrId)
2308      raise NotImplementError, "need to define `__item_pathname'"
2309    end
2310    private :__conf_cmd, :__item_pathname
2311  
2312    def tagfont_configinfo(tagOrId)
2313      pathname = __item_pathname(tagOrId)
2314      ret = TkFont.used_on(pathname)
2315      if ret == nil
2316        ret = TkFont.init_widget_font(pathname, self.path, 
2317                                      __conf_cmd(0), __conf_cmd(1), tagOrId)
2318      end
2319      ret
2320    end
2321    alias tagfontobj tagfont_configinfo
2322  
2323    def tagfont_configure(tagOrId, slot)
2324      pathname = __item_pathname(tagOrId)
2325      slot = _symbolkey2str(slot)
2326      if (fnt = slot.delete('font'))
2327        if fnt.kind_of? TkFont
2328          return fnt.call_font_configure(pathname, self.path, 
2329                                         __conf_cmd(0), __conf_cmd(1), 
2330                                         tagOrId, slot)
2331        else
2332          latintagfont_configure(tagOrId, fnt) if fnt
2333        end
2334      end
2335      if (ltn = slot.delete('latinfont'))
2336        latintagfont_configure(tagOrId, ltn) if ltn
2337      end
2338      if (ltn = slot.delete('asciifont'))
2339        latintagfont_configure(tagOrId, ltn) if ltn
2340      end
2341      if (knj = slot.delete('kanjifont'))
2342        kanjitagfont_configure(tagOrId, knj) if knj
2343      end
2344  
2345      tk_call(self.path, __conf_cmd(0), __conf_cmd(1), 
2346              tagOrId, *hash_kv(slot)) if slot != {}
2347      self
2348    end
2349  
2350    def latintagfont_configure(tagOrId, ltn, keys=nil)
2351      fobj = tagfontobj(tagOrId)
2352      if ltn.kind_of? TkFont
2353        conf = {}
2354        ltn.latin_configinfo.each{|key,val| conf[key] = val if val != []}
2355        if conf == {}
2356          fobj.latin_replace(ltn)
2357          fobj.latin_configure(keys) if keys
2358        elsif keys
2359          fobj.latin_configure(conf.update(keys))
2360        else
2361          fobj.latin_configure(conf)
2362        end
2363      else
2364        fobj.latin_replace(ltn)
2365      end
2366    end
2367    alias asciitagfont_configure latintagfont_configure
2368  
2369    def kanjitagfont_configure(tagOrId, knj, keys=nil)
2370      fobj = tagfontobj(tagOrId)
2371      if knj.kind_of? TkFont
2372        conf = {}
2373        knj.kanji_configinfo.each{|key,val| conf[key] = val if val != []}
2374        if conf == {}
2375          fobj.kanji_replace(knj)
2376          fobj.kanji_configure(keys) if keys
2377        elsif keys
2378          fobj.kanji_configure(conf.update(keys))
2379        else
2380          fobj.kanji_configure(conf)
2381        end
2382      else
2383        fobj.kanji_replace(knj)
2384      end
2385    end
2386  
2387    def tagfont_copy(tagOrId, window, wintag=nil)
2388      if wintag
2389        window.tagfontobj(wintag).configinfo.each{|key,value|
2390          tagfontobj(tagOrId).configure(key,value)
2391        }
2392        tagfontobj(tagOrId).replace(window.tagfontobj(wintag).latin_font, 
2393                                  window.tagfontobj(wintag).kanji_font)
2394      else
2395        window.tagfont(wintag).configinfo.each{|key,value|
2396          tagfontobj(tagOrId).configure(key,value)
2397        }
2398        tagfontobj(tagOrId).replace(window.fontobj.latin_font, 
2399                                  window.fontobj.kanji_font)
2400      end
2401    end
2402  
2403    def latintagfont_copy(tagOrId, window, wintag=nil)
2404      if wintag
2405        tagfontobj(tagOrId).latin_replace(window.tagfontobj(wintag).latin_font)
2406      else
2407        tagfontobj(tagOrId).latin_replace(window.fontobj.latin_font)
2408      end
2409    end
2410    alias asciitagfont_copy latintagfont_copy
2411  
2412    def kanjitagfont_copy(tagOrId, window, wintag=nil)
2413      if wintag
2414        tagfontobj(tagOrId).kanji_replace(window.tagfontobj(wintag).kanji_font)
2415      else
2416        tagfontobj(tagOrId).kanji_replace(window.fontobj.kanji_font)
2417      end
2418    end
2419  end
2420  
2421  class TkObject<TkKernel
2422    include Tk
2423    include TkTreatFont
2424    include TkBindCore
2425  
2426    def path
2427      return @path
2428    end
2429  
2430    def epath
2431      return @path
2432    end
2433  
2434    def to_eval
2435      @path
2436    end
2437  
2438    def tk_send(cmd, *rest)
2439      tk_call path, cmd, *rest
2440    end
2441    private :tk_send
2442  
2443    def method_missing(id, *args)
2444      name = id.id2name
2445      case args.length
2446      when 1
2447        configure name, args[0]
2448      when 0
2449        begin
2450          cget name
2451        rescue
2452          fail NameError, "undefined local variable or method `#{name}' for #{self.to_s}", error_at
2453        end
2454      else
2455        fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at
2456      end
2457    end
2458  
2459    def [](id)
2460      cget id
2461    end
2462  
2463    def []=(id, val)
2464      configure id, val
2465    end
2466  
2467    def cget(slot)
2468      case slot.to_s
2469      when 'text', 'label', 'show', 'data', 'file'
2470        tk_call path, 'cget', "-#{slot}"
2471      else
2472        tk_tcl2ruby tk_call(path, 'cget', "-#{slot}")
2473      end
2474    end
2475  
2476    def configure(slot, value=None)
2477      if slot.kind_of? Hash
2478        if (slot['font'] || slot[:font] || 
2479            slot['kanjifont'] || slot[:kanjifont] || 
2480            slot['latinfont'] || slot[:latinfont] || 
2481            slot['asciifont'] || slot[:asciifont] )
2482          font_configure(slot)
2483        else
2484          tk_call path, 'configure', *hash_kv(slot)
2485        end
2486  
2487      else
2488        if (slot == 'font' || slot == :font || 
2489            slot == 'kanjifont' || slot == :kanjifont || 
2490            slot == 'latinfont' || slot == :latinfont || 
2491            slot == 'asciifont' || slot == :asciifont )
2492          if value == None
2493            fontobj
2494          else
2495            font_configure({slot=>value})
2496          end
2497        else
2498          tk_call path, 'configure', "-#{slot}", value
2499        end
2500      end
2501    end
2502  
2503    def configure_cmd(slot, value)
2504      configure slot, install_cmd(value)
2505    end
2506  
2507    def configinfo(slot = nil)
2508      if slot == 'font' || slot == :font || 
2509         slot == 'kanjifont' || slot == :kanjifont
2510        fontobj
2511      else
2512        if slot
2513          case slot.to_s
2514          when 'text', 'label', 'show', 'data', 'file'
2515            conf = tk_split_simplelist(tk_send('configure', "-#{slot}") )
2516          else
2517            conf = tk_split_list(tk_send('configure', "-#{slot}") )
2518          end
2519          conf[0] = conf[0][1..-1]
2520          conf
2521        else
2522          ret = tk_split_simplelist(tk_send('configure') ).collect{|conflist|
2523            conf = tk_split_simplelist(conflist)
2524            conf[0] = conf[0][1..-1]
2525            case conf[0]
2526            when 'text', 'label', 'show', 'data', 'file'
2527            else
2528              if conf[3]
2529                if conf[3].index('{')
2530                  conf[3] = tk_split_list(conf[3]) 
2531                else
2532                  conf[3] = tk_tcl2ruby(conf[3]) 
2533                end
2534              end
2535              if conf[4]
2536                if conf[4].index('{')
2537                  conf[4] = tk_split_list(conf[4]) 
2538                else
2539                  conf[4] = tk_tcl2ruby(conf[4]) 
2540                end
2541              end
2542            end
2543            conf
2544          }
2545          fontconf = ret.assoc('font')
2546          if fontconf
2547            ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'}
2548            fontconf[4] = fontobj
2549            ret.push(fontconf)
2550          else
2551            ret
2552          end
2553        end
2554      end
2555    end
2556  
2557    def event_generate(context, keys=nil)
2558      if keys
2559        tk_call('event', 'generate', path, 
2560                "<#{tk_event_sequence(context)}>", *hash_kv(keys))
2561      else
2562        tk_call('event', 'generate', path, "<#{tk_event_sequence(context)}>")
2563      end
2564    end
2565  
2566    def tk_trace_variable(v)
2567      unless v.kind_of?(TkVariable)
2568        fail ArgumentError, format("requires TkVariable given %s", v.type)
2569      end
2570      v
2571    end
2572    private :tk_trace_variable
2573  
2574    def destroy
2575      tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id
2576    end
2577  end
2578  
2579  class TkWindow<TkObject
2580    extend TkBindCore
2581  
2582    def initialize(parent=nil, keys=nil)
2583      if parent.kind_of? Hash
2584        keys = _symbolkey2str(parent)
2585        keydup = true
2586        parent = keys.delete('parent')
2587        widgetname = keys.delete('widgetname')
2588        install_win(if parent then parent.path end, widgetname)
2589      elsif keys
2590        keys = _symbolkey2str(keys)
2591        widgetname = keys.delete('widgetname')
2592        install_win(if parent then parent.path end, widgetname)
2593      else
2594        install_win(if parent then parent.path end)
2595      end
2596      if self.method(:create_self).arity == 0
2597        p 'create_self has no arg' if $DEBUG
2598        create_self
2599        if keys
2600          # tk_call @path, 'configure', *hash_kv(keys)
2601          configure(keys)
2602        end
2603      else
2604        p 'create_self has args' if $DEBUG
2605        fontkeys = {}
2606        if keys
2607          ['font', 'kanjifont', 'latinfont', 'asciifont'].each{|key|
2608            fontkeys[key] = keys.delete(key) if keys.key?(key)
2609          }
2610        end
2611        create_self(keys)
2612        font_configure(fontkeys) unless fontkeys.empty?
2613      end
2614    end
2615  
2616    def create_self
2617    end
2618    private :create_self
2619  
2620    def pack(keys = nil)
2621      tk_call 'pack', epath, *hash_kv(keys)
2622      self
2623    end
2624  
2625    def unpack
2626      tk_call 'pack', 'forget', epath
2627      self
2628    end
2629    alias pack_forget unpack
2630  
2631    def pack_config(slot, value=None)
2632      if slot.kind_of? Hash
2633        tk_call 'pack', 'configure', epath, *hash_kv(slot)
2634      else
2635        tk_call 'pack', 'configure', epath, "-#{slot}", value
2636      end
2637    end
2638  
2639    def pack_info()
2640      ilist = list(tk_call('pack', 'info', epath))
2641      info = {}
2642      while key = ilist.shift
2643        info[key[1..-1]] = ilist.shift
2644      end
2645      return info
2646    end
2647  
2648    def pack_propagate(mode = nil)
2649      if mode
2650        tk_call('pack', 'propagate', epath, mode)
2651      else
2652        bool(tk_call('pack', 'propagate', epath))
2653      end
2654    end
2655  
2656    def pack_slaves()
2657      list(tk_call('pack', 'slaves', epath))
2658    end
2659  
2660    def grid(keys = nil)
2661      tk_call 'grid', epath, *hash_kv(keys)
2662      self
2663    end
2664  
2665    def ungrid
2666      tk_call 'grid', 'forget', epath
2667      self
2668    end
2669    alias grid_forget ungrid
2670  
2671    def grid_bbox(*args)
2672      list(tk_call('grid', 'bbox', epath, *args))
2673    end
2674  
2675    def grid_config(slot, value=None)
2676      if slot.kind_of? Hash
2677        tk_call 'grid', 'configure', epath, *hash_kv(slot)
2678      else
2679        tk_call 'grid', 'configure', epath, "-#{slot}", value
2680      end
2681    end
2682  
2683    def grid_columnconfig(index, keys)
2684      tk_call('grid', 'columnconfigure', epath, index, *hash_kv(keys))
2685    end
2686  
2687    def grid_rowconfig(index, keys)
2688      tk_call('grid', 'rowconfigure', epath, index, *hash_kv(keys))
2689    end
2690  
2691    def grid_columnconfiginfo(index, slot=nil)
2692      if slot
2693        tk_call('grid', 'columnconfigure', epath, index, "-#{slot}")
2694      else
2695        ilist = list(tk_call('grid', 'columnconfigure', epath, index))
2696        info = {}
2697        while key = ilist.shift
2698          info[key[1..-1]] = ilist.shift
2699        end
2700        info
2701      end
2702    end
2703  
2704    def grid_rowconfiginfo(index, slot=nil)
2705      if slot
2706        tk_call('grid', 'rowconfigure', epath, index, "-#{slot}")
2707      else
2708        ilist = list(tk_call('grid', 'rowconfigure', epath, index))
2709        info = {}
2710        while key = ilist.shift
2711          info[key[1..-1]] = ilist.shift
2712        end
2713        info
2714      end
2715    end
2716  
2717    def grid_info()
2718      list(tk_call('grid', 'info', epath))
2719    end
2720  
2721    def grid_location(x, y)
2722      list(tk_call('grid', 'location', epath, x, y))
2723    end
2724  
2725    def grid_propagate(mode=nil)
2726      if mode
2727        tk_call('grid', 'propagate', epath, mode)
2728      else
2729        bool(tk_call('grid', 'propagate', epath))
2730      end
2731    end
2732  
2733    def grid_remove()
2734      tk_call 'grid', 'remove', epath
2735    end
2736  
2737    def grid_size()
2738      tk_call 'grid', 'size', epath
2739    end
2740  
2741    def grid_slaves(args)
2742      list(tk_call('grid', 'slaves', epath, *hash_kv(args)))
2743    end
2744  
2745    def place(keys = nil)
2746      tk_call 'place', epath, *hash_kv(keys)
2747      self
2748    end
2749  
2750    def unplace
2751      tk_call 'place', 'forget', epath
2752      self
2753    end
2754    alias place_forget unplace
2755  
2756    def place_config(slot, value=None)
2757      if slot.kind_of? Hash
2758        tk_call 'place', 'configure', epath, *hash_kv(slot)
2759      else
2760        tk_call 'place', 'configure', epath, "-#{slot}", value
2761      end
2762    end
2763  
2764    def place_configinfo(slot = nil)
2765      # for >= Tk8.4a2 ?
2766      if slot
2767        conf = tk_split_list(tk_call('place', 'configure', epath, "-#{slot}") )
2768        conf[0] = conf[0][1..-1]
2769        conf
2770      else
2771        tk_split_simplelist(tk_call('place', 
2772                                    'configure', epath)).collect{|conflist|
2773          conf = tk_split_simplelist(conflist)
2774          conf[0] = conf[0][1..-1]
2775          conf
2776        }
2777      end
2778    end
2779  
2780    def place_info()
2781      ilist = list(tk_call('place', 'info', epath))
2782      info = {}
2783      while key = ilist.shift
2784        info[key[1..-1]] = ilist.shift
2785      end
2786      return info
2787    end
2788  
2789    def place_slaves()
2790      list(tk_call('place', 'slaves', epath))
2791    end
2792  
2793    def focus(force=false)
2794      if force
2795        tk_call 'focus', '-force', path
2796      else
2797        tk_call 'focus', path
2798      end
2799      self
2800    end
2801  
2802    def grab(*args)
2803      if !args or args.length == 0
2804        tk_call 'grab', 'set', path
2805      elsif args.length == 1
2806        case args[0]
2807        when 'global', :global
2808          return(tk_call('grab', 'set', '-global', path))
2809        when 'release', :release
2810          return tk_call('grab', 'release', path)
2811        else
2812          val = tk_call('grab', args[0], path)
2813        end
2814        case args[0]
2815        when 'current', :current
2816          return window(val)
2817        when 'status', :status
2818          return val
2819        end
2820      else
2821        fail ArgumentError, 'wrong # of args'
2822      end
2823    end
2824  
2825    def lower(below=None)
2826      tk_call 'lower', epath, below
2827      self
2828    end
2829    def raise(above=None)
2830      tk_call 'raise', epath, above
2831      self
2832    end
2833  
2834    def command(cmd=Proc.new)
2835      configure_cmd 'command', cmd
2836    end
2837  
2838    def colormodel model=None
2839      tk_call 'tk', 'colormodel', path, model
2840      self
2841    end
2842  
2843    def destroy
2844      tk_call 'destroy', epath
2845      if @cmdtbl
2846        for id in @cmdtbl
2847          uninstall_cmd id
2848        end
2849      end
2850      uninstall_win
2851    end
2852  
2853    def wait_visibility
2854      tk_call 'tkwait', 'visibility', path
2855    end
2856    alias wait wait_visibility
2857  
2858    def wait_destroy
2859      tk_call 'tkwait', 'window', epath
2860    end
2861  
2862    def bindtags(taglist=nil)
2863      if taglist
2864        fail ArgumentError unless taglist.kind_of? Array
2865        tk_call('bindtags', path, taglist)
2866      else
2867        list(tk_call('bindtags', path)).collect{|tag|
2868          if tag.kind_of?(String) 
2869            if cls = WidgetClassNames[tag]
2870              cls
2871            elsif btag = TkBindTag.id2obj(tag)
2872              btag
2873            else
2874              tag
2875            end
2876          else
2877            tag
2878          end
2879        }
2880      end
2881    end
2882  end
2883  
2884  class TkRoot<TkWindow
2885    include Wm
2886    ROOT = []
2887    def TkRoot.new
2888      return ROOT[0] if ROOT[0]
2889      new = super
2890      ROOT[0] = new
2891      Tk_WINDOWS["."] = new
2892    end
2893  
2894    WidgetClassName = 'Tk'.freeze
2895    WidgetClassNames[WidgetClassName] = self
2896    def self.to_eval
2897      WidgetClassName
2898    end
2899  
2900    def create_self
2901      @path = '.'
2902    end
2903    def path
2904      "."
2905    end
2906  end
2907  
2908  class TkToplevel<TkWindow
2909    include Wm
2910  
2911    WidgetClassName = 'Toplevel'.freeze
2912    WidgetClassNames[WidgetClassName] = self
2913    def self.to_eval
2914      WidgetClassName
2915    end
2916  
2917  ################# old version
2918  #  def initialize(parent=nil, screen=nil, classname=nil, keys=nil)
2919  #    if screen.kind_of? Hash
2920  #      keys = screen.dup
2921  #    else
2922  #      @screen = screen
2923  #    end
2924  #    @classname = classname
2925  #    if keys.kind_of? Hash
2926  #      keys = keys.dup
2927  #      @classname = keys.delete('classname') if keys.key?('classname')
2928  #      @colormap  = keys.delete('colormap')  if keys.key?('colormap')
2929  #      @container = keys.delete('container') if keys.key?('container')
2930  #      @screen    = keys.delete('screen')    if keys.key?('screen')
2931  #      @use       = keys.delete('use')       if keys.key?('use')
2932  #      @visual    = keys.delete('visual')    if keys.key?('visual')
2933  #    end
2934  #    super(parent, keys)
2935  #  end
2936  #
2937  #  def create_self
2938  #    s = []
2939  #    s << "-class"     << @classname if @classname
2940  #    s << "-colormap"  << @colormap  if @colormap
2941  #    s << "-container" << @container if @container
2942  #    s << "-screen"    << @screen    if @screen 
2943  #    s << "-use"       << @use       if @use
2944  #    s << "-visual"    << @visual    if @visual
2945  #    tk_call 'toplevel', @path, *s
2946  #  end
2947  #################
2948  
2949    def initialize(parent=nil, screen=nil, classname=nil, keys=nil)
2950      if parent.kind_of? Hash
2951        keys = _symbolkey2str(parent)
2952        @screen    = keys['screen']
2953        @classname = keys['class']
2954        @colormap  = keys['colormap']
2955        @container = keys['container']
2956        @screen    = keys['screen']
2957        @use       = keys['use']
2958        @visual    = keys['visual']
2959        super(keys)
2960        return
2961      end
2962      if screen.kind_of? Hash
2963        keys = _symbolkey2str(screen)
2964      else
2965        @screen = screen
2966      end
2967      @classname = classname
2968      if keys.kind_of? Hash
2969        keys = _symbolkey2str(keys)
2970        if keys.key?(:classname) || keys.key?('classname')
2971          keys['class'] = keys.delete('classname')
2972        end
2973        @classname = keys['class']
2974        @colormap  = keys['colormap']
2975        @container = keys['container']
2976        @screen    = keys['screen']
2977        @use       = keys['use']
2978        @visual    = keys['visual']
2979      end
2980      super(parent, keys)
2981    end
2982  
2983    def create_self(keys)
2984      if keys and keys != None
2985        tk_call 'toplevel', @path, *hash_kv(keys)
2986      else
2987        tk_call 'toplevel', @path
2988      end
2989    end
2990  
2991    def specific_class
2992      @classname
2993    end
2994  end
2995  
2996  class TkFrame<TkWindow
2997    WidgetClassName = 'Frame'.freeze
2998    WidgetClassNames[WidgetClassName] = self
2999    def self.to_eval
3000      WidgetClassName
3001    end
3002  
3003  ################# old version
3004  #  def initialize(parent=nil, keys=nil)
3005  #    if keys.kind_of? Hash
3006  #      keys = keys.dup
3007  #      @classname = keys.delete('classname') if keys.key?('classname')
3008  #      @colormap  = keys.delete('colormap')  if keys.key?('colormap')
3009  #      @container = keys.delete('container') if keys.key?('container')
3010  #      @visual    = keys.delete('visual')    if keys.key?('visual')
3011  #    end
3012  #    super(parent, keys)
3013  #  end
3014  #
3015  #  def create_self
3016  #    s = []
3017  #    s << "-class"     << @classname if @classname
3018  #    s << "-colormap"  << @colormap  if @colormap
3019  #    s << "-container" << @container if @container
3020  #    s << "-visual"    << @visual    if @visual
3021  #    tk_call 'frame', @path, *s
3022  #  end
3023  #################
3024  
3025    def initialize(parent=nil, keys=nil)
3026      if parent.kind_of? Hash
3027        keys = _symbolkey2str(parent)
3028      else
3029        if keys
3030          keys = _symbolkey2str(keys)
3031          keys['parent'] = parent
3032        else
3033          keys = {'parent'=>parent}
3034        end
3035      end
3036      if keys.key?('classname')
3037         keys['class'] = keys.delete('classname')
3038      end
3039      @classname = keys['class']
3040      @colormap  = keys['colormap']
3041      @container = keys['container']
3042      @visual    = keys['visual']
3043      super(keys)
3044    end
3045  
3046    def create_self(keys)
3047      if keys and keys != None
3048        tk_call 'frame', @path, *hash_kv(keys)
3049      else
3050        tk_call 'frame', @path
3051      end
3052    end
3053  end
3054  
3055  class TkLabel<TkWindow
3056    WidgetClassName = 'Label'.freeze
3057    WidgetClassNames[WidgetClassName] = self
3058    def self.to_eval
3059      WidgetClassName
3060    end
3061    def create_self(keys)
3062      if keys and keys != None
3063        tk_call 'label', @path, *hash_kv(keys)
3064      else
3065        tk_call 'label', @path
3066      end
3067    end
3068    def textvariable(v)
3069      configure 'textvariable', tk_trace_variable(v)
3070    end
3071  end
3072  
3073  class TkButton<TkLabel
3074    WidgetClassNames['Button'] = self
3075    def TkButton.to_eval
3076      'Button'
3077    end
3078    def create_self(keys)
3079      if keys and keys != None
3080        tk_call 'button', @path, *hash_kv(keys)
3081      else
3082        tk_call 'button', @path
3083      end
3084    end
3085    def invoke
3086      tk_send 'invoke'
3087    end
3088    def flash
3089      tk_send 'flash'
3090    end
3091  end
3092  
3093  class TkRadioButton<TkButton
3094    WidgetClassNames['Radiobutton'] = self
3095    def TkRadioButton.to_eval
3096      'Radiobutton'
3097    end
3098    def create_self(keys)
3099      if keys and keys != None
3100        tk_call 'radiobutton', @path, *hash_kv(keys)
3101      else
3102        tk_call 'radiobutton', @path
3103      end
3104    end
3105    def deselect
3106      tk_send 'deselect'
3107    end
3108    def select
3109      tk_send 'select'
3110    end
3111    def variable(v)
3112      configure 'variable', tk_trace_variable(v)
3113    end
3114  end
3115  TkRadiobutton = TkRadioButton
3116  
3117  class TkCheckButton<TkRadioButton
3118    WidgetClassNames['Checkbutton'] = self
3119    def TkCheckButton.to_eval
3120      'Checkbutton'
3121    end
3122    def create_self(keys)
3123      if keys and keys != None
3124        tk_call 'checkbutton', @path, *hash_kv(keys)
3125      else
3126        tk_call 'checkbutton', @path
3127      end
3128    end
3129    def toggle
3130      tk_send 'toggle'
3131    end
3132  end
3133  TkCheckbutton = TkCheckButton
3134  
3135  class TkMessage<TkLabel
3136    WidgetClassNames['Message'] = self
3137    def TkMessage.to_eval
3138      'Message'
3139    end
3140    def create_self(keys)
3141      if keys and keys != None
3142        tk_call 'message', @path, *hash_kv(keys)
3143      else
3144        tk_call 'message', @path
3145      end
3146    end
3147  end
3148  
3149  class TkScale<TkWindow
3150    WidgetClassName = 'Scale'.freeze
3151    WidgetClassNames[WidgetClassName] = self
3152    def self.to_eval
3153      WidgetClassName
3154    end
3155  
3156    def create_self(keys)
3157      if keys and keys != None
3158        tk_call 'scale', @path, *hash_kv(keys)
3159      else
3160        tk_call 'scale', @path
3161      end
3162    end
3163  
3164    def get(x=None, y=None)
3165      number(tk_send('get', x, y))
3166    end
3167  
3168    def coords(val=None)
3169      tk_split_list(tk_send('coords', val))
3170    end
3171  
3172    def identify(x, y)
3173      tk_send('identify', x, y)
3174    end
3175  
3176    def set(val)
3177      tk_send "set", val
3178    end
3179  
3180    def value
3181      get
3182    end
3183  
3184    def value= (val)
3185      set val
3186    end
3187  end
3188  
3189  class TkScrollbar<TkWindow
3190    WidgetClassName = 'Scrollbar'.freeze
3191    WidgetClassNames[WidgetClassName] = self
3192    def self.to_eval
3193      WidgetClassName
3194    end
3195  
3196    def create_self(keys)
3197      if keys and keys != None
3198        tk_call 'scrollbar', @path, *hash_kv(keys)
3199      else
3200        tk_call 'scrollbar', @path
3201      end
3202    end
3203  
3204    def delta(deltax=None, deltay=None)
3205      number(tk_send('delta', deltax, deltay))
3206    end
3207  
3208    def fraction(x=None, y=None)
3209      number(tk_send('fraction', x, y))
3210    end
3211  
3212    def identify(x, y)
3213      tk_send('identify', x, y)
3214    end
3215  
3216    def get
3217      ary1 = tk_send('get').split
3218      ary2 = []
3219      for i in ary1
3220        ary2.push number(i)
3221      end
3222      ary2
3223    end
3224  
3225    def set(first, last)
3226      tk_send "set", first, last
3227    end
3228  
3229    def activate(element=None)
3230      tk_send('activate', element)
3231    end
3232  end
3233  
3234  class TkTextWin<TkWindow
3235    def create_self
3236      fail TypeError, "TkTextWin is abstract class"
3237    end
3238  
3239    def bbox(index)
3240      tk_send 'bbox', index
3241    end
3242    def delete(first, last=None)
3243      tk_send 'delete', first, last
3244    end
3245    def get(*index)
3246      tk_send 'get', *index
3247    end
3248    def index(index)
3249      tk_send 'index', index
3250    end
3251    def insert(index, chars, *args)
3252      tk_send 'insert', index, chars, *args
3253    end
3254    def scan_mark(x, y)
3255      tk_send 'scan', 'mark', x, y
3256    end
3257    def scan_dragto(x, y)
3258      tk_send 'scan', 'dragto', x, y
3259    end
3260    def see(index)
3261      tk_send 'see', index
3262    end
3263  end
3264  
3265  module TkTreatListItemFont
3266    include TkTreatItemFont
3267  
3268    ItemCMD = ['itemconfigure', TkComm::None]
3269    def __conf_cmd(idx)
3270      ItemCMD[idx]
3271    end
3272  
3273    def __item_pathname(tagOrId)
3274      self.path + ';' + tagOrId.to_s
3275    end
3276  end
3277  
3278  class TkListbox<TkTextWin
3279    include TkTreatListItemFont
3280    include Scrollable
3281  
3282    WidgetClassNames['Listbox'] = self
3283    def TkListbox.to_eval
3284      'Listbox'
3285    end
3286    def create_self(keys)
3287      if keys and keys != None
3288        tk_call 'listbox', @path, *hash_kv(keys)
3289      else
3290        tk_call 'listbox', @path
3291      end
3292    end
3293  
3294    def activate(y)
3295      tk_send 'activate', y
3296    end
3297    def curselection
3298      list(tk_send('curselection'))
3299    end
3300    def get(*index)
3301      v = tk_send('get', *index)
3302      if index.size == 1
3303        v
3304      else
3305        tk_split_simplelist(v)
3306      end
3307    end
3308    def nearest(y)
3309      tk_send('nearest', y).to_i
3310    end
3311    def size
3312      tk_send('size').to_i
3313    end
3314    def selection_anchor(index)
3315      tk_send 'selection', 'anchor', index
3316    end
3317    def selection_clear(first, last=None)
3318      tk_send 'selection', 'clear', first, last
3319    end
3320    def selection_includes(index)
3321      bool(tk_send('selection', 'includes', index))
3322    end
3323    def selection_set(first, last=None)
3324      tk_send 'selection', 'set', first, last
3325    end
3326  
3327    def itemcget(index, key)
3328      case key.to_s
3329      when 'text', 'label', 'show'
3330        tk_send 'itemcget', index, "-#{key}"
3331      else
3332        tk_tcl2ruby tk_send('itemcget', index, "-#{key}")
3333      end
3334    end
3335    def itemconfigure(index, key, val=None)
3336      if key.kind_of? Hash
3337        if (key['font'] || key[:font] || 
3338            key['kanjifont'] || key[:kanjifont] || 
3339            key['latinfont'] || key[:latinfont] || 
3340            key['asciifont'] || key[:asciifont] )
3341          tagfont_configure(index, _symbolkey2str(key))
3342        else
3343          tk_send 'itemconfigure', index, *hash_kv(key)
3344        end
3345  
3346      else
3347        if (key == 'font' || key == :font || 
3348            key == 'kanjifont' || key == :kanjifont || 
3349            key == 'latinfont' || key == :latinfont || 
3350            key == 'asciifont' || key == :asciifont )
3351          tagfont_configure(index, {key=>val})
3352        else
3353          tk_call 'itemconfigure', index, "-#{key}", val
3354        end
3355      end
3356    end
3357  
3358    def itemconfiginfo(index, key=nil)
3359      if key
3360        case key.to_s
3361        when 'text', 'label', 'show'
3362          conf = tk_split_simplelist(tk_send('itemconfigure',index,"-#{key}"))
3363        else
3364          conf = tk_split_list(tk_send('itemconfigure',index,"-#{key}"))
3365        end
3366        conf[0] = conf[0][1..-1]
3367        conf
3368      else
3369        tk_split_simplelist(tk_send('itemconfigure', index)).collect{|conflist|
3370          conf = tk_split_simplelist(conflist)
3371          conf[0] = conf[0][1..-1]
3372          case conf[0]
3373          when 'text', 'label', 'show'
3374          else
3375            if conf[3]
3376              if conf[3].index('{')
3377                conf[3] = tk_split_list(conf[3]) 
3378              else
3379                conf[3] = tk_tcl2ruby(conf[3]) 
3380              end
3381            end
3382            if conf[4]
3383              if conf[4].index('{')
3384                conf[4] = tk_split_list(conf[4]) 
3385              else
3386                conf[4] = tk_tcl2ruby(conf[4]) 
3387              end
3388            end
3389          end
3390          conf
3391        }
3392      end
3393    end
3394  end
3395  
3396  module TkTreatMenuEntryFont
3397    include TkTreatItemFont
3398  
3399    ItemCMD = ['entryconfigure', TkComm::None]
3400    def __conf_cmd(idx)
3401      ItemCMD[idx]
3402    end
3403    
3404    def __item_pathname(tagOrId)
3405      self.path + ';' + tagOrId.to_s
3406    end
3407  end
3408  
3409  class TkMenu<TkWindow
3410    include TkTreatMenuEntryFont
3411  
3412    WidgetClassName = 'Menu'.freeze
3413    WidgetClassNames[WidgetClassName] = self
3414    def self.to_eval
3415      WidgetClassName
3416    end
3417    def create_self(keys)
3418      if keys and keys != None
3419        tk_call 'menu', @path, *hash_kv(keys)
3420      else
3421        tk_call 'menu', @path
3422      end
3423    end
3424    def activate(index)
3425      tk_send 'activate', index
3426    end
3427    def add(type, keys=nil)
3428      tk_send 'add', type, *hash_kv(keys)
3429    end
3430    def index(index)
3431      tk_send 'index', index
3432    end
3433    def invoke(index)
3434      tk_send 'invoke', index
3435    end
3436    def insert(index, type, keys=nil)
3437      tk_send 'insert', index, type, *hash_kv(keys)
3438    end
3439    def delete(index, last=None)
3440      tk_send 'delete', index, last
3441    end
3442    def popup(x, y, index=None)
3443      tk_call 'tk_popup', path, x, y, index
3444    end
3445    def post(x, y)
3446      tk_send 'post', x, y
3447    end
3448    def postcascade(index)
3449      tk_send 'postcascade', index
3450    end
3451    def postcommand(cmd=Proc.new)
3452      configure_cmd 'postcommand', cmd
3453    end
3454    def tearoffcommand(cmd=Proc.new)
3455      configure_cmd 'tearoffcommand', cmd
3456    end
3457    def menutype(index)
3458      tk_send 'type', index
3459    end
3460    def unpost
3461      tk_send 'unpost'
3462    end
3463    def yposition(index)
3464      number(tk_send('yposition', index))
3465    end
3466    def entrycget(index, key)
3467      case key.to_s
3468      when 'text', 'label', 'show'
3469        tk_send 'entrycget', index, "-#{key}"
3470      else
3471        tk_tcl2ruby tk_send('entrycget', index, "-#{key}")
3472      end
3473    end
3474    def entryconfigure(index, key, val=None)
3475      if key.kind_of? Hash
3476        if (key['font'] || key[:font] || 
3477            key['kanjifont'] || key[:kanjifont] || 
3478            key['latinfont'] || key[:latinfont] || 
3479            key['asciifont'] || key[:asciifont])
3480          tagfont_configure(index, _symbolkey2str(key))
3481        else
3482          tk_send 'entryconfigure', index, *hash_kv(key)
3483        end
3484  
3485      else
3486        if (key == 'font' || key == :font || 
3487            key == 'kanjifont' || key == :kanjifont || 
3488            key == 'latinfont' || key == :latinfont || 
3489            key == 'asciifont' || key == :asciifont )
3490          tagfont_configure({key=>val})
3491        else
3492          tk_call 'entryconfigure', index, "-#{key}", val
3493        end
3494      end
3495    end
3496  
3497    def entryconfiginfo(index, key=nil)
3498      if key
3499        case key.to_s
3500        when 'text', 'label', 'show'
3501          conf = tk_split_simplelist(tk_send('entryconfigure',index,"-#{key}"))
3502        else
3503          conf = tk_split_list(tk_send('entryconfigure',index,"-#{key}"))
3504        end
3505        conf[0] = conf[0][1..-1]
3506        conf
3507      else
3508        tk_split_simplelist(tk_send('entryconfigure', index)).collect{|conflist|
3509          conf = tk_split_simplelist(conflist)
3510          conf[0] = conf[0][1..-1]
3511          case conf[0]
3512          when 'text', 'label', 'show'
3513          else
3514            if conf[3]
3515              if conf[3].index('{')
3516                conf[3] = tk_split_list(conf[3]) 
3517              else
3518                conf[3] = tk_tcl2ruby(conf[3]) 
3519              end
3520            end
3521            if conf[4]
3522              if conf[4].index('{')
3523                conf[4] = tk_split_list(conf[4]) 
3524              else
3525                conf[4] = tk_tcl2ruby(conf[4]) 
3526              end
3527            end
3528          end
3529          conf
3530        }
3531      end
3532    end
3533  end
3534  
3535  class TkMenuClone<TkMenu
3536    def initialize(parent, type=None)
3537      widgetname = nil
3538      if parent.kind_of? Hash
3539        keys = _symbolkey2str(parent)
3540        parent = keys.delete('parent')
3541        widgetname = keys.delete('widgetname')
3542        type = keys.delete('type'); type = None unless type
3543      end
3544      unless parent.kind_of?(TkMenu)
3545        fail ArgumentError, "parent must be TkMenu"
3546      end
3547      @parent = parent
3548      install_win(@parent.path, widgetname)
3549      tk_call @parent.path, 'clone', @path, type
3550    end
3551  end
3552  
3553  module TkSystemMenu
3554    def initialize(parent, keys=nil)
3555      if parent.kind_of? Hash
3556        keys = _symbolkey2str(parent)
3557        parent = keys.delete('parent')
3558      end
3559      fail unless parent.kind_of? TkMenu
3560      @path = format("%s.%s", parent.path, self.type::SYSMENU_NAME)
3561      TkComm::Tk_WINDOWS[@path] = self
3562      if self.method(:create_self).arity == 0
3563        p 'create_self has no arg' if $DEBUG
3564        create_self
3565        configure(keys) if keys
3566      else
3567        p 'create_self has an arg' if $DEBUG
3568        create_self(keys)
3569      end
3570    end
3571  end
3572  
3573  class TkSysMenu_Help<TkMenu
3574    # for all platform
3575    include TkSystemMenu
3576    SYSMENU_NAME = 'help'
3577  end
3578  
3579  class TkSysMenu_System<TkMenu
3580    # for Windows
3581    include TkSystemMenu
3582    SYSMENU_NAME = 'system'
3583  end
3584  
3585  class TkSysMenu_Apple<TkMenu
3586    # for Machintosh
3587    include TkSystemMenu
3588    SYSMENU_NAME = 'apple'
3589  end
3590  
3591  class TkMenubutton<TkLabel
3592    WidgetClassNames['Menubutton'] = self
3593    def TkMenubutton.to_eval
3594      'Menubutton'
3595    end
3596    def create_self(keys)
3597      if keys and keys != None
3598        tk_call 'menubutton', @path, *hash_kv(keys)
3599      else
3600        tk_call 'menubutton', @path
3601      end
3602    end
3603  end
3604  
3605  class TkOptionMenubutton<TkMenubutton
3606    class OptionMenu<TkMenu
3607      def initialize(parent)
3608        @path = parent.path + '.menu'
3609        TkComm::Tk_WINDOWS[@path] = self
3610      end
3611    end
3612  
3613    def initialize(parent=nil, var=TkVariable.new, firstval=nil, *vals)
3614      if parent.kind_of Hash
3615         keys = _symbolkey2str(parent)
3616         parent = keys['parent']
3617         var = keys['variable'] if keys['variable']
3618         firstval, *vals = keys['values']
3619      end
3620      fail unless var.kind_of? TkVariable
3621      @variable = var
3622      firstval = @variable.value unless firstval
3623      @variable.value = firstval
3624      install_win(if parent then parent.path end)
3625      @menu = OptionMenu.new(self)
3626      tk_call 'tk_optionMenu', @path, @variable.id, firstval, *vals
3627    end
3628  
3629    def value
3630      @variable.value
3631    end
3632  
3633    def activate(index)
3634      @menu.activate(index)
3635    end
3636    def add(value)
3637      @menu.add('radiobutton', 'variable'=>@variable, 
3638                'label'=>value, 'value'=>value)
3639    end
3640    def index(index)
3641      @menu.index(index)
3642    end
3643    def invoke(index)
3644      @menu.invoke(index)
3645    end
3646    def insert(index, value)
3647      @menu.add(index, 'radiobutton', 'variable'=>@variable, 
3648                'label'=>value, 'value'=>value)
3649    end
3650    def delete(index, last=None)
3651      @menu.delete(index, last)
3652    end
3653    def yposition(index)
3654      @menu.yposition(index)
3655    end
3656    def menucget(index, key)
3657      @menu.cget(index, key)
3658    end
3659    def menuconfigure(index, key, val=None)
3660      @menu.configure(index, key, val)
3661    end
3662    def menuconfiginfo(index, key=nil)
3663      @menu.configinfo(index, key)
3664    end
3665    def entrycget(index, key)
3666      @menu.entrycget(index, key)
3667    end
3668    def entryconfigure(index, key, val=None)
3669      @menu.entryconfigure(index, key, val)
3670    end
3671    def entryconfiginfo(index, key=nil)
3672      @menu.entryconfiginfo(index, key)
3673    end
3674  end
3675  
3676  module TkComposite
3677    include Tk
3678    extend Tk
3679  
3680    def initialize(parent=nil, *args)
3681      if parent.kind_of? Hash
3682        keys = _symbolkey2str(parent)
3683        parent = keys['parent']
3684        keys['parent'] = @frame = TkFrame.new(parent)
3685        @path = @epath = @frame.path
3686        initialize_composite(keys)
3687      else
3688        @frame = TkFrame.new(parent)
3689        @path = @epath = @frame.path
3690        initialize_composite(*args)
3691      end
3692    end
3693  
3694    def epath
3695      @epath
3696    end
3697  
3698    def initialize_composite(*args) end
3699    private :initialize_composite
3700  
3701    def delegate(option, *wins)
3702      unless @delegates
3703        @delegates = {} 
3704        @delegates['DEFAULT'] = @frame
3705      end
3706      if @delegates[option].kind_of?(Array)
3707        for i in wins
3708          @delegates[option].push(i)
3709        end
3710      else
3711        @delegates[option] = wins
3712      end
3713    end
3714  
3715    def configure(slot, value=None)
3716      if slot.kind_of? Hash
3717        slot.each{|slot,value| configure slot, value}
3718      else
3719        if @delegates and @delegates[slot]
3720          for i in @delegates[slot]
3721            if not i
3722              i = @delegates['DEFALUT']
3723              redo
3724            else
3725              last = i.configure(slot, value)
3726            end
3727          end
3728          last
3729        else
3730          super
3731        end
3732      end
3733    end
3734  end
3735  
3736  module TkClipboard
3737    include Tk
3738    extend Tk
3739  
3740    def clear
3741      tk_call 'clipboard', 'clear'
3742    end
3743    def get
3744      begin
3745        tk_call 'selection', 'get', '-selection', 'CLIPBOARD'
3746      rescue
3747        ''
3748      end
3749    end
3750    def set(data)
3751      clear
3752      append(data)
3753    end
3754    def append(data)
3755      tk_call 'clipboard', 'append', data
3756    end
3757  
3758    module_function :clear, :set, :get, :append
3759  end
3760  
3761  autoload :TkCanvas, 'tkcanvas'
3762  autoload :TkImage, 'tkcanvas'
3763  autoload :TkBitmapImage, 'tkcanvas'
3764  autoload :TkPhotoImage, 'tkcanvas'
3765  autoload :TkEntry, 'tkentry'
3766  autoload :TkSpinbox, 'tkentry'
3767  autoload :TkText, 'tktext'
3768  autoload :TkDialog, 'tkdialog'
3769  autoload :TkWarning, 'tkdialog'
3770  autoload :TkMenubar, 'tkmenubar'
3771  autoload :TkAfter, 'tkafter'
3772  autoload :TkPalette, 'tkpalette'
3773  autoload :TkFont, 'tkfont'
3774  autoload :TkVirtualEvent, 'tkvirtevent'
3775  autoload :TkBgError, 'tkbgerror'
3776  autoload :TkManageFocus, 'tkmngfocus'
3777  autoload :TkPalette, 'tkpalette'
3778  autoload :TkWinDDE, 'tkwinpkg'
3779  autoload :TkWinRegistry, 'tkwinpkg'
3780  autoload :TkMacResource, 'tkmacpkg'