# # tk.rb - Tk interface modue using tcltklib # $Date$ # by Yukihiro Matsumoto # use Shigehiro's tcltklib require "tcltklib" require "tkutil" module TkComm WidgetClassNames = {} None = Object.new def None.to_s 'None' end Tk_CMDTBL = {} Tk_WINDOWS = {} def error_at frames = caller() frames.delete_if do |c| c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+! end frames end private :error_at def _genobj_for_tkwidget(path) return TkRoot.new if path == '.' begin tk_class = TkCore::INTERP._invoke('winfo', 'class', path) rescue return path end ruby_class = WidgetClassNames[tk_class] gen_class_name = ruby_class.name + 'GeneratedOnTk' unless Object.const_defined? gen_class_name eval "class #{gen_class_name}<#{ruby_class.name} def initialize(path) @path=path Tk_WINDOWS[@path] = self end end" end eval "#{gen_class_name}.new('#{path}')" end def tk_tcl2ruby(val) if val =~ /^rb_out (c\d+)/ return Tk_CMDTBL[$1] end if val.include? ?\s return val.split.collect{|v| tk_tcl2ruby(v)} end case val when /^@font/ TkFont.get_obj(val) when /^-?\d+$/ val.to_i when /^\./ Tk_WINDOWS[val] ? Tk_WINDOWS[val] : _genobj_for_tkwidget(val) when / / val.split.collect{|elt| tk_tcl2ruby(elt) } when /^-?\d+\.\d*$/ val.to_f else val end end def tk_split_list(str) return [] if str == "" idx = str.index('{') return tk_tcl2ruby(str) unless idx list = tk_tcl2ruby(str[0,idx]) list = [] if list == "" str = str[idx+1..-1] i = -1 brace = 1 str.each_byte {|c| i += 1 brace += 1 if c == ?{ brace -= 1 if c == ?} break if brace == 0 } if str[0, i] == ' ' list.push ' ' else list.push tk_split_list(str[0, i]) end list += tk_split_list(str[i+1..-1]) list end def tk_split_simplelist(str) return [] if str == "" idx = str.index('{') return str.split unless idx list = str[0,idx].split str = str[idx+1..-1] i = -1 brace = 1 str.each_byte {|c| i += 1 brace += 1 if c == ?{ brace -= 1 if c == ?} break if brace == 0 } if i == 0 list.push '' elsif str[0, i] == ' ' list.push ' ' else list.push str[0..i-1] end list += tk_split_simplelist(str[i+1..-1]) list end private :tk_tcl2ruby, :tk_split_list, :tk_split_simplelist def hash_kv(keys) conf = [] if keys and keys != None for k, v in keys conf.push("-#{k}") conf.push(v) end end conf end private :hash_kv def array2tk_list(ary) ary.collect{|e| if e.kind_of? Array "{#{array2tk_list(e)}}" elsif e.kind_of? Hash "{#{e.to_a.collect{|ee| array2tk_list(ee)}.join(' ')}}" else s = _get_eval_string(e) (s.index(/\s/))? "{#{s}}": s end }.join(" ") end private :array2tk_list def bool(val) case val when "1", 1, 'yes', 'true' TRUE else FALSE end end def number(val) case val when /^-?\d+$/ val.to_i when /^-?\d+\.\d*$/ val.to_f else val end end def string(val) if val == "{}" '' elsif val[0] == ?{ val[1..-2] else val end end def list(val) tk_split_list(val).to_a end def window(val) Tk_WINDOWS[val] end def procedure(val) if val =~ /^rb_out (c\d+)/ Tk_CMDTBL[$1] else nil end end private :bool, :number, :string, :list, :window, :procedure def _get_eval_string(str) return nil if str == None if str.kind_of?(String) # do nothing elsif str.kind_of?(Hash) str = hash_kv(str).join(" ") elsif str.kind_of?(Array) str = array2tk_list(str) elsif str.kind_of?(Proc) str = install_cmd(str) elsif str == nil str = "" elsif str == false str = "0" elsif str == true str = "1" elsif (str.respond_to?(:to_eval)) str = str.to_eval() else str = str.to_s() end return str end private :_get_eval_string def ruby2tcl(v) if v.kind_of?(Hash) v = hash_kv(v) v.flatten! v.collect{|e|ruby2tcl(e)} else _get_eval_string(v) end end private :ruby2tcl Tk_IDs = [0, 0] # [0]-cmdid, [1]-winid def _curr_cmd_id id = format("c%.4d", Tk_IDs[0]) end def _next_cmd_id id = _curr_cmd_id Tk_IDs[0] += 1 id end def install_cmd(cmd) return '' if cmd == '' id = _next_cmd_id Tk_CMDTBL[id] = cmd @cmdtbl = [] unless @cmdtbl @cmdtbl.push id return format("rb_out %s", id); end def uninstall_cmd(id) id = $1 if /rb_out (c\d+)/ =~ id Tk_CMDTBL[id] = nil end private :install_cmd, :uninstall_cmd def install_win(ppath) id = format("w%.4d", Tk_IDs[1]) Tk_IDs[1] += 1 if !ppath or ppath == "." @path = format(".%s", id); else @path = format("%s.%s", ppath, id) end Tk_WINDOWS[@path] = self end def uninstall_win() Tk_WINDOWS[@path] = nil end class Event def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy) @serial = seq @num = b @focus = (f == 1) @height = h @keycode = k @state = s @time = t @width = w @x = x @y = y @char = aa @send_event = (ee == 1) @keysym = kk @keysym_num = nn @type = tt @widget = ww @x_root = xx @y_root = yy end attr :serial attr :num attr :focus attr :height attr :keycode attr :state attr :time attr :width attr :x attr :y attr :char attr :send_event attr :keysym attr :keysym_num attr :type attr :widget attr :x_root attr :y_root end def install_bind(cmd, args=nil) if args id = install_cmd(proc{|arg| TkUtil.eval_cmd cmd, *arg }) id + " " + args else id = install_cmd(proc{|arg| TkUtil.eval_cmd cmd, Event.new(*arg) }) id + ' %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y' end end def tk_event_sequence(context) if context.kind_of? TkVirtualEvent context = context.path end if context.kind_of? Array context = context.collect{|ev| if context.kind_of? TkVirtualEvent ev.path else ev end }.join("><") end if /,/ =~ context context = context.split(/\s*,\s*/).join("><") else context end end def _bind_core(mode, what, context, cmd, args=nil) id = install_bind(cmd, args) if cmd begin tk_call(*(what + ["<#{tk_event_sequence(context)}>", mode + id])) rescue uninstall_cmd(id) if cmd fail end end def _bind(what, context, cmd, args=nil) _bind_core('', what, context, cmd, args) end def _bind_append(what, context, cmd, args=nil) _bind_core('+', what, context, cmd, args) end def _bind_remove(what, context) tk_call(*(what + ["<#{tk_event_sequence(context)}>", ''])) end def _bindinfo(what, context=nil) if context tk_call(*what+["<#{tk_event_sequence(context)}>"]).collect {|cmdline| if cmdline =~ /^rb_out (c\d+)\s+(.*)$/ [Tk_CMDTBL[$1], $2] else cmdline end } else tk_split_list(tk_call(*what)).collect{|seq| seq[1..-2].gsub(/>", *hash_kv(keys)) else tk_call('event', 'generate', window, "<#{tk_event_sequence(context)}>") end end def messageBox(keys) tk_call 'tk_messageBox', *hash_kv(keys) end def getOpenFile(keys = nil) tk_call 'tk_getOpenFile', *hash_kv(keys) end def getSaveFile(keys = nil) tk_call 'tk_getSaveFile', *hash_kv(keys) end def chooseColor(keys = nil) tk_call 'tk_chooseColor', *hash_kv(keys) end def tk_call(*args) print args.join(" "), "\n" if $DEBUG args.collect! {|x|ruby2tcl(x)} args.compact! args.flatten! begin res = INTERP._invoke(*args) rescue NameError err = $! begin args.unshift "unknown" res = INTERP._invoke(*args) rescue fail unless /^invalid command/ =~ $! fail err end end if INTERP._return_value() != 0 fail RuntimeError, res, error_at end print "==> ", res, "\n" if $DEBUG return res end end module Tk include TkCore extend Tk TCL_VERSION = INTERP._invoke("info", "tclversion") TK_VERSION = INTERP._invoke("set", "tk_version") JAPANIZED_TK = (INTERP._invoke("info", "commands", "kanji") != "") def root TkRoot.new end def bell tk_call 'bell' end def Tk.focus(display=nil) if display == nil r = tk_call('focus') else r = tk_call('focus', '-displayof', display) end tk_tcl2ruby(r) end def Tk.focus_lastfor(win) tk_tcl2ruby(tk_call('focus', '-lastfor', win)) end def Tk.show_kinsoku(mode='both') begin if /^8\.*/ === TK_VERSION && JAPANIZED_TK tk_split_simplelist(tk_call('kinsoku', 'show', mode)) end rescue end end def Tk.add_kinsoku(chars, mode='both') begin if /^8\.*/ === TK_VERSION && JAPANIZED_TK tk_split_simplelist(tk_call('kinsoku', 'add', mode, *(chars.split('')))) else [] end rescue [] end end def Tk.delete_kinsoku(chars, mode='both') begin if /^8\.*/ === TK_VERSION && JAPANIZED_TK tk_split_simplelist(tk_call('kinsoku', 'delete', mode, *(chars.split('')))) end rescue end end def toUTF8(str,encoding) INTERP._toUTF8(str,encoding) end def fromUTF8(str,encoding) INTERP._fromUTF8(str,encoding) end module Scrollable def xscrollcommand(cmd=Proc.new) configure_cmd 'xscrollcommand', cmd end def yscrollcommand(cmd=Proc.new) configure_cmd 'yscrollcommand', cmd end def xview(*index) v = tk_send('xview', *index) list(v) if index.size == 0 end def yview(*index) v = tk_send('yview', *index) list(v) if index.size == 0 end def xscrollbar(bar=nil) if bar @xscrollbar = bar @xscrollbar.orient 'horizontal' self.xscrollcommand {|arg| @xscrollbar.set *arg} @xscrollbar.command {|arg| self.xview *arg} end @xscrollbar end def yscrollbar(bar=nil) if bar @yscrollbar = bar @yscrollbar.orient 'vertical' self.yscrollcommand {|arg| @yscrollbar.set *arg} @yscrollbar.command {|arg| self.yview *arg} end @yscrollbar end end module Wm include TkComm def aspect(*args) w = tk_call('wm', 'aspect', path, *args) list(w) if args.length == 0 end def client(name=None) tk_call 'wm', 'client', path, name end def colormapwindows(*args) list(tk_call('wm', 'colormapwindows', path, *args)) end def wm_command(value=None) string(tk_call('wm', 'command', path, value)) end def deiconify tk_call 'wm', 'deiconify', path end def focusmodel(*args) tk_call 'wm', 'focusmodel', path, *args end def frame tk_call('wm', 'frame', path) end def geometry(*args) tk_call('wm', 'geometry', path, *args) end def grid(*args) w = tk_call('wm', 'grid', path, *args) list(w) if args.size == 0 end def group(*args) w = tk_call 'wm', 'group', path, *args window(w) if args.size == 0 end def iconbitmap(*args) tk_call 'wm', 'iconbitmap', path, *args end def iconify tk_call 'wm', 'iconify', path end def iconmask(*args) tk_call 'wm', 'iconmask', path, *args end def iconname(*args) tk_call 'wm', 'iconname', path, *args end def iconposition(*args) w = tk_call('wm', 'iconposition', path, *args) list(w) if args.size == 0 end def iconwindow(*args) w = tk_call('wm', 'iconwindow', path, *args) window(w) if args.size == 0 end def maxsize(*args) w = tk_call('wm', 'maxsize', path, *args) list(w) if args.size == 0 end def minsize(*args) w = tk_call('wm', 'minsize', path, *args) list(w) if args.size == 0 end def overrideredirect(bool=None) if bool == None bool(tk_call('wm', 'overrideredirect', path)) else tk_call 'wm', 'overrideredirect', path, bool end end def positionfrom(*args) tk_call 'wm', 'positionfrom', path, *args end def protocol(name=nil, cmd=nil) if cmd tk_call('wm', 'protocol', path, name, cmd) elsif name result = tk_call('wm', 'protocol', path, name) (result == "")? nil : tk_tcl2ruby(result) else tk_split_simplelist(tk_call('wm', 'protocol', path)) end end def resizable(*args) w = tk_call('wm', 'resizable', path, *args) if args.length == 0 list(w).collect{|e| bool(e)} end end def sizefrom(*args) tk_call('wm', 'sizefrom', path, *args) end def state tk_call 'wm', 'state', path end def title(*args) tk_call 'wm', 'title', path, *args end def transient(*args) window(tk_call 'wm', 'transient', path, *args) end def withdraw tk_call 'wm', 'withdraw', path end end end module TkBindCore def bind(context, cmd=Proc.new, args=nil) Tk.bind(to_eval, context, cmd, args) end def bind_append(context, cmd=Proc.new, args=nil) Tk.bind_append(to_eval, context, cmd, args) end def bind_remove(context) Tk.bind_remove(to_eval, context) end def bindinfo(context=nil) Tk.bindinfo(to_eval, context) end end class TkBindTag include TkBindCore BTagID_TBL = {} Tk_BINDTAG_ID = ["btag00000"] def TkBindTag.id2obj(id) BTagID_TBL[id]? BTagID_TBL[id]: id end def initialize(*args) @id = Tk_BINDTAG_ID[0] Tk_BINDTAG_ID[0] = Tk_BINDTAG_ID[0].succ BTagID_TBL[@id] = self bind(*args) if args != [] end def to_eval @id end def inspect format "#", @id end end class TkBindTagAll", @id end def ==(other) case other when TkVariable self.equal(self) when String self.to_s == other when Integer self.to_i == other when Float self.to_f == other when Array self.to_a == other else false end end def to_a list(value) end def to_eval @id end def unset(elem=nil) if elem INTERP._eval(format('global %s; unset %s(%s)', @id, @id, tk_tcl2ruby(elem))) else INTERP._eval(format('global %s; unset %s', @id, @id)) end end alias remove unset def trace_callback(elem, op) if @trace_var.kind_of? Array @trace_var.each{|m,e| e.call(self,elem,op) if m.index(op)} end if elem.kind_of? String if @trace_elem[elem].kind_of? Array @trace_elem[elem].each{|m,e| e.call(self,elem,op) if m.index(op)} end end end def trace(opts, cmd) @trace_var = [] if @trace_var == nil opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') @trace_var.unshift([opts,cmd]) if @trace_opts == nil TkVar_CB_TBL[@id] = self @trace_opts = opts Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') else newopts = @trace_opts.dup opts.each_byte{|c| newopts += c.chr unless newopts.index(c)} if newopts != @trace_opts Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var') @trace_opts.replace(newopts) Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') end end end def trace_element(elem, opts, cmd) @trace_elem = {} if @trace_elem == nil @trace_elem[elem] = [] if @trace_elem[elem] == nil opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') @trace_elem[elem].unshift([opts,cmd]) if @trace_opts == nil TkVar_CB_TBL[@id] = self @trace_opts = opts Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') else newopts = @trace_opts.dup opts.each_byte{|c| newopts += c.chr unless newopts.index(c)} if newopts != @trace_opts Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var') @trace_opts.replace(newopts) Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') end end end def trace_vinfo return [] unless @trace_var @trace_var.dup end def trace_vinfo_for_element(elem) return [] unless @trace_elem return [] unless @trace_elem[elem] @trace_elem[elem].dup end def trace_vdelete(opts,cmd) return unless @trace_var.kind_of? Array opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') idx = -1 newopts = '' @trace_var.each_with_index{|i,e| if idx < 0 && e[0] == opts && e[1] == cmd idx = i next end e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} } if idx >= 0 @trace_var.delete_at(idx) else return end @trace_elem.each{|elem| @trace_elem[elem].each{|e| e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} } } newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('') if newopts != @trace_opts Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var') @trace_opts.replace(newopts) if @trace_opts != '' Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') end end end def trace_vdelete_for_element(elem,opts,cmd) return unless @trace_elem.kind_of? Hash return unless @trace_elem[elem].kind_of? Array opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') idx = -1 @trace_elem[elem].each_with_index{|i,e| if idx < 0 && e[0] == opts && e[1] == cmd idx = i next end } if idx >= 0 @trace_elem[elem].delete_at(idx) else return end newopts = '' @trace_var.each{|e| e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} } @trace_elem.each{|elem| @trace_elem[elem].each{|e| e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} } } newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('') if newopts != @trace_opts Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var') @trace_opts.replace(newopts) if @trace_opts != '' Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') end end end end class TkVarAccessvalue}) end else tk_call path, 'configure', "-#{slot}", value end end end def configure_cmd(slot, value) configure slot, install_cmd(value) end def configinfo(slot = nil) if slot == 'font' || slot == 'kanjifont' fontobj else if slot conf = tk_split_list(tk_send('configure', "-#{slot}") ) conf[0] = conf[0][1..-1] conf else ret = tk_split_list(tk_send('configure') ).collect{|conf| conf[0] = conf[0][1..-1] conf } if ret.assoc('font') ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'} ret.push(['font', fontobj]) else ret end end end end def event_generate(context, keys=nil) if keys tk_call('event', 'generate', path, "<#{tk_event_sequence(context)}>", *hash_kv(keys)) else tk_call('event', 'generate', path, "<#{tk_event_sequence(context)}>") end end def tk_trace_variable(v) unless v.kind_of?(TkVariable) fail ArgumentError, format("requires TkVariable given %s", v.type) end v end private :tk_trace_variable def destroy tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id end end class TkWindowval}) else tk_call 'itemconfigure', index, "-#{key}", val end end end def itemconfiginfo(index, key=nil) if key conf = tk_split_list(tk_send('itemconfigure',index,"-#{key}")) conf[0] = conf[0][1..-1] conf else tk_split_list(tk_send('itemconfigure', index)).collect{|conf| conf[0] = conf[0][1..-1] conf } end end end module TkTreatMenuEntryFont def tagfont_configinfo(index) pathname = self.path + ';' + index ret = TkFont.used_on(pathname) if ret == nil ret = TkFont.init_widget_font(pathname, self.path, 'entryconfigure', index) end ret end alias tagfontobj tagfont_configinfo def tagfont_configure(index, slot) pathname = self.path + ';' + index if (fnt = slot.delete('font')) if fnt.kind_of? TkFont return fnt.call_font_configure(pathname, self.path,'entryconfigure',index,slot) else latintagfont_configure(index, fnt) if fnt end end if (ltn = slot.delete('latinfont')) latintagfont_configure(index, ltn) if ltn end if (ltn = slot.delete('asciifont')) latintagfont_configure(index, ltn) if ltn end if (knj = slot.delete('kanjifont')) kanjitagfont_configure(index, knj) if knj end tk_call(self.path, 'entryconfigure', index, *hash_kv(slot)) if slot != {} self end def latintagfont_configure(index, ltn, keys=nil) fobj = tagfontobj(index) if ltn.kind_of? TkFont conf = {} ltn.latin_configinfo.each{|key,val| conf[key] = val if val != []} if conf == {} fobj.latin_replace(ltn) fobj.latin_configure(keys) if keys elsif keys fobj.latin_configure(conf.update(keys)) else fobj.latin_configure(conf) end else fobj.latin_replace(ltn) end end alias asciitagfont_configure latintagfont_configure def kanjitagfont_configure(index, knj, keys=nil) fobj = tagfontobj(index) if knj.kind_of? TkFont conf = {} knj.kanji_configinfo.each{|key,val| conf[key] = val if val != []} if conf == {} fobj.kanji_replace(knj) fobj.kanji_configure(keys) if keys elsif keys fobj.kanji_configure(conf.update(keys)) else fobj.kanji_configure(conf) end else fobj.kanji_replace(knj) end end def tagfont_copy(index, window, wintag=nil) if wintag window.tagfontobj(wintag).configinfo.each{|key,value| tagfontobj(index).configure(key,value) } tagfontobj(index).replace(window.tagfontobj(wintag).latin_font, window.tagfontobj(wintag).kanji_font) else window.tagfont(wintag).configinfo.each{|key,value| tagfontobj(index).configure(key,value) } tagfontobj(index).replace(window.fontobj.latin_font, window.fontobj.kanji_font) end end def latintagfont_copy(index, window, wintag=nil) if wintag tagfontobj(index).latin_replace(window.tagfontobj(wintag).latin_font) else tagfontobj(index).latin_replace(window.fontobj.latin_font) end end alias asciitagfont_copy latintagfont_copy def kanjitagfont_copy(index, window, wintag=nil) if wintag tagfontobj(index).kanji_replace(window.tagfontobj(wintag).kanji_font) else tagfontobj(index).kanji_replace(window.fontobj.kanji_font) end end end class TkMenuval}) else tk_call 'entryconfigure', index, "-#{key}", val end end end def entryconfiginfo(index, key=nil) if key conf = tk_split_list(tk_send('entryconfigure',index,"-#{key}")) conf[0] = conf[0][1..-1] conf else tk_split_list(tk_send('entryconfigure', index)).collect{|conf| conf[0] = conf[0][1..-1] conf } end end end module TkSystemMenu def initialize(parent, keys=nil) fail unless parent.kind_of? TkMenu @path = format("%s.%s", parent.path, self.type::SYSMENU_NAME) TkComm::Tk_WINDOWS[@path] = self create_self configure(keys) if keys end end class TkSysMenu_Help@variable, 'label'=>value, 'value'=>value) end def index(index) @menu.index(index) end def invoke(index) @menu.invoke(index) end def insert(index, value) @menu.add(index, 'radiobutton', 'variable'=>@variable, 'label'=>value, 'value'=>value) end def delete(index, last=None) @menu.delete(index, last) end def yposition(index) @menu.yposition(index) end def menucget(index, key) @menu.cget(index, key) end def menuconfigure(index, key, val=None) @menu.configure(index, key, val) end def menuconfiginfo(index, key=nil) @menu.configinfo(index, key) end def entrycget(index, key) @menu.entrycget(index, key) end def entryconfigure(index, key, val=None) @menu.entryconfigure(index, key, val) end def entryconfiginfo(index, key=nil) @menu.entryconfiginfo(index, key) end end module TkComposite include Tk extend Tk def initialize(parent=nil, *args) @frame = TkFrame.new(parent) @path = @epath = @frame.path initialize_composite(*args) end def epath @epath end def initialize_composite(*args) end private :initialize_composite def delegate(option, *wins) unless @delegates @delegates = {} @delegates['DEFAULT'] = @frame end if @delegates[option].kind_of?(Array) for i in wins @delegates[option].push(i) end else @delegates[option] = wins end end def configure(slot, value=None) if slot.kind_of? Hash slot.each{|slot,value| configure slot, value} else if @delegates and @delegates[slot] for i in @delegates[slot] if not i i = @delegates['DEFALUT'] redo else last = i.configure(slot, value) end end last else super end end end end module TkClipboard include Tk extend Tk def clear tk_call 'clipboard', 'clear' end def get begin tk_call 'selection', 'get', '-selection', 'CLIPBOARD' rescue '' end end def set(data) clear append(data) end def append(data) tk_call 'clipboard', 'append', data end module_function :clear, :set, :get, :append end autoload :TkCanvas, 'tkcanvas' autoload :TkImage, 'tkcanvas' autoload :TkBitmapImage, 'tkcanvas' autoload :TkPhotoImage, 'tkcanvas' autoload :TkEntry, 'tkentry' autoload :TkText, 'tktext' autoload :TkDialog, 'tkdialog' autoload :TkMenubar, 'tkmenubar' autoload :TkAfter, 'tkafter' autoload :TkPalette, 'tkpalette' autoload :TkFont, 'tkfont' autoload :TkVirtualEvent, 'tkvirtevent'