diff options
author | nagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-07-12 23:08:32 +0000 |
---|---|---|
committer | nagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-07-12 23:08:32 +0000 |
commit | ab91f35f8f2229085b20a7cfa081f8b85453b718 (patch) | |
tree | 09bc05d679d0f224a29fee44d10beea321bdc0b5 /ext/tk/lib/tk/autoload.rb | |
parent | bc25af2dbfcdd82d1df693683174e01516a669eb (diff) | |
download | ruby-ab91f35f8f2229085b20a7cfa081f8b85453b718.tar.gz ruby-ab91f35f8f2229085b20a7cfa081f8b85453b718.tar.xz ruby-ab91f35f8f2229085b20a7cfa081f8b85453b718.zip |
* ext/tk/extconf.rb: New strategy for searching Tcl/Tk libraries.
* ext/tk/*: Support new features of Tcl/Tk8.6b1 and minor bug fixes.
( [KNOWN BUG] Ruby/Tk on Ruby 1.9 will not work on Cygwin. )
* ext/tk/*: Unify sources between Ruby 1.8 & 1.9.
Improve default_widget_set handling.
* ext/tk/*: Multi-TkInterpreter (multi-tk.rb) works on Ruby 1.8 & 1.9.
( [KNOWN BUG] On Ruby 1.8, join to a long term Thread on Tk
callbacks may freeze. On Ruby 1.9, cannot create a second
master interpreter (creating slaves are OK); supported master
interpreter is the default master interpreter only. )
* ext/tk/lib/tkextlib/*: Update supported versions of Tk extensions.
Tcllib 1.8/Tklib 0.4.1 ==> Tcllib 1.11.1/Tklib 0.5
BWidgets 1.7 ==> BWidgets 1.8
TkTable 2.9 ==> TkTable 2.10
TkTreeCtrl 2005-12-02 ==> TkTreeCtrl 2.2.9
Tile 0.8.0/8.5.1 ==> Tile 0.8.3/8.6b1
IncrTcl 2005-02-14 ==> IncrTcl 2008-12-15
TclX 2005-02-07 ==> TclX 2008-12-15
Trofs 0.4.3 ==> Trofs 0.4.4
git-svn-id: http://svn.ruby-lang.org/repos/ruby/trunk@24063 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/tk/lib/tk/autoload.rb')
-rw-r--r-- | ext/tk/lib/tk/autoload.rb | 398 |
1 files changed, 372 insertions, 26 deletions
diff --git a/ext/tk/lib/tk/autoload.rb b/ext/tk/lib/tk/autoload.rb index df888eb92..2ebee9ea2 100644 --- a/ext/tk/lib/tk/autoload.rb +++ b/ext/tk/lib/tk/autoload.rb @@ -27,6 +27,8 @@ def TkPlace(*args); TkPlace.configure(*args); end ############################################ # classes on Tk module module Tk + autoload :Busy, 'tk/busy' + autoload :Button, 'tk/button' autoload :Canvas, 'tk/canvas' @@ -319,9 +321,16 @@ module Tk @TOPLEVEL_ALIAS_SETUP_PROC = {} + @AUTOLOAD_FILE_SYM_TABLE = Hash.new{|h,k| h[k]={}} # TABLE[file][sym] -> obj + @current_default_widget_set = nil + + module TOPLEVEL_ALIASES; end end +class Object + include Tk::TOPLEVEL_ALIASES +end ############################################ # methods to control default widget set @@ -343,50 +352,387 @@ class << Tk _replace_toplevel_aliases(target) end - def __set_toplevel_aliases__(target, obj, *symbols) + def widget_set_symbols + @TOPLEVEL_ALIAS_TABLE.keys + end + + def toplevel_aliases_on_widget_set(widget_set) + if (tbl = @TOPLEVEL_ALIAS_TABLE[widget_set.to_sym]) + tbl.collect{|k, v| (v.nil?)? nil: k}.compact + else + fail ArgumentError, "unknown widget_set #{widget_set.to_sym.inspect}" + end + end + + def __toplevel_alias_setup_proc__(*target_list, &cmd) + target_list.each{|target| @TOPLEVEL_ALIAS_SETUP_PROC[target.to_sym] = cmd} + end + + def topobj_defined?(sym) #=> alias_filename or object or false + Object.autoload?(sym) || + (Object.const_defined?(sym) && Object.const_get(sym)) + end + def topalias_defined?(sym) #=> alias_filename or object or false + Tk::TOPLEVEL_ALIASES.autoload?(sym) || + (Tk::TOPLEVEL_ALIASES.const_defined?(sym) && + Tk::TOPLEVEL_ALIASES.const_get(sym)) + end + def define_topobj(sym, obj) + if obj.kind_of? String + # obj is an autoload path + Object.autoload(sym, obj) + unless Object.autoload?(sym) + # file is autoloaded? + if @AUTOLOAD_FILE_SYM_TABLE.has_key?(obj) && + (loaded_obj = @AUTOLOAD_FILE_SYM_TABLE[obj][sym]) + Object.const_set(sym, loaded_obj) + else + fail ArgumentError, "cannot define autoload file (already loaded?)" + end + end + else + # object + Object.const_set(sym, obj) + end + end + def define_topalias(sym, obj) + if obj.kind_of? String + # obj is an autoload path + Tk::TOPLEVEL_ALIASES.autoload(sym, obj) + unless Tk::TOPLEVEL_ALIASES.autoload?(sym) + # file is autoloaded? + if @AUTOLOAD_FILE_SYM_TABLE.has_key?(obj) && + (loaded_obj = @AUTOLOAD_FILE_SYM_TABLE[obj][sym]) + Tk::TOPLEVEL_ALIASES.const_set(sym, loaded_obj) + else + fail ArgumentError, "cannot define autoload file (already loaded?)" + end + end + else + # object + Tk::TOPLEVEL_ALIASES.const_set(sym, obj) + end + end + def replace_topobj(sym, obj) #=> old_obj (alias_filename or object) or nil + if old_obj = topobj_defined?(sym) + Object.class_eval{remove_const sym} rescue nil # ignore err + end + define_topobj(sym, obj) + old_obj + end + def replace_topalias(sym, obj) #=> old_obj (alias_filename or object) or nil + if old_obj = topalias_defined?(sym) + Tk::TOPLEVEL_ALIASES.module_eval{remove_const sym} rescue nil #ignore err + end + define_topalias(sym, obj) + old_obj + end + private :topobj_defined?, :topalias_defined? + private :define_topobj, :define_topalias + private :replace_topobj, :replace_topalias + + def __regist_toplevel_aliases__(target, obj, *symbols) + # initial regist @TOPLEVEL_ALIAS_TABLE[target = target.to_sym] ||= {} symbols.each{|sym| @TOPLEVEL_ALIAS_TABLE[target][sym = sym.to_sym] = obj - # if @current_default_widget_set == target - if @TOPLEVEL_ALIAS_OWNER[sym] == target - Object.class_eval{remove_const sym} if Object.const_defined?(sym) - Object.const_set(sym, obj) + if !topalias_defined?(sym) || target == @current_default_widget_set + @TOPLEVEL_ALIAS_OWNER[sym] = target + replace_topalias(sym, obj) + replace_topobj(sym, obj) unless obj.kind_of?(String) # NOT autoload end } end - ################################### - private - def _replace_toplevel_aliases(target) - # check already autoloaded - if (table = @TOPLEVEL_ALIAS_TABLE[current = @current_default_widget_set]) - table.each{|sym, file| - if !Object.autoload?(sym) && Object.const_defined?(sym) && - @TOPLEVEL_ALIAS_TABLE[current][sym].kind_of?(String) - # autoload -> class - @TOPLEVEL_ALIAS_TABLE[current][sym] = Object.const_get(sym) + def regist_sym_for_loaded_file(auto, obj, sym) + @AUTOLOAD_FILE_SYM_TABLE[auto][sym] = obj + + reg = /^#{Regexp.quote(auto)}(\.rb|\.so|)$/ + @TOPLEVEL_ALIAS_TABLE.each_key{|set| + if @TOPLEVEL_ALIAS_TABLE[set][sym] =~ reg + @TOPLEVEL_ALIAS_TABLE[set][sym] = obj + if @TOPLEVEL_ALIAS_OWNER[sym].nil? || @TOPLEVEL_ALIAS_OWNER[sym] == set + replace_topalias(sym, obj) + replace_topobj(sym, obj) if set == @current_default_widget_set end - } + end + } + if (f = Object.autoload?(sym)) && f =~ reg + replace_topobj(sym, obj) end + if (f = Tk::TOPLEVEL_ALIASES.autoload?(sym)) && f =~ reg + replace_topalias(sym, obj) + end + end + private :regist_sym_for_loaded_file + + def set_topalias(target, obj, sym) + # obj is a kind of String : define autoload path + # Class : use the class object + if target == @current_default_widget_set + case @TOPLEVEL_ALIAS_OWNER[sym] + when false + # Object::sym is out of control. --> not change + # Make ALIAS::sym under control, because target widget set is current. + # Keep OWNER[sym] + @TOPLEVEL_ALIAS_TABLE[target][sym] = obj + replace_topalias(sym, obj) + + when target + if current_obj = topobj_defined?(sym) + if current_obj == obj + # Make current_obj under control. + # Keep Object::sym. + # Keep OWNER[sym]. + @TOPLEVEL_ALIAS_TABLE[target][sym] = obj + replace_topalias(sym, obj) + + else # current_obj != obj + if current_obj == topalias_defined?(sym) + # Change controlled object + # Keep OWNER[sym]. + @TOPLEVEL_ALIAS_TABLE[target][sym] = obj + replace_topalias(sym, obj) + replace_topobj(sym, obj) + + else # current_obj != topalias_defined?(sym) + # Maybe current_obj is defined by user. --> OWNER[sym] = faise + # Keep Object::sym. + @TOPLEVEL_ALIAS_OWNER[sym] = false + @TOPLEVEL_ALIAS_TABLE[target][sym] = obj + replace_topalias(sym, obj) + end + end + + else # NOT topobj_defined?(sym) + # New definition for sym at target. + # Keep OWNER[sym]. + @TOPLEVEL_ALIAS_TABLE[target][sym] = obj + replace_topalias(sym, obj) + define_topobj(sym, obj) + end + + when nil + # New definition for sym at target. + @TOPLEVEL_ALIAS_OWNER[sym] = target + @TOPLEVEL_ALIAS_TABLE[target][sym] = obj + replace_topalias(sym, obj) + + else # others + # Maybe planning to make sym under control. + @TOPLEVEL_ALIAS_OWNER[sym] = target + @TOPLEVEL_ALIAS_TABLE[target][sym] = obj + replace_topalias(sym, obj) + replace_topobj(sym, obj) + end + + else # target != @current_default_widget_set + case @TOPLEVEL_ALIAS_OWNER[sym] + when false + # Object::sym is out of control. --> not change + if topalias_defined?(sym) + # ALIAS[sym] may be defined by other widget set. + # Keep Object::sym (even if it is not defined) + # Keep ALIAS[sym]. + # Keep OWNER[sym]. + @TOPLEVEL_ALIAS_TABLE[target][sym] = obj + + else # NOT topalias_defined?(sym) + # Nobody controls ALIAS[sym]. + # At leaset, current widget set doesn't control ALIAS[sym]. + # Keep Object::sym (even if it is not defined) + # Keep OWNER[sym]. + @TOPLEVEL_ALIAS_TABLE[target][sym] = obj + define_topalias(sym, obj) + end + + when target + # Maybe change controlled object, because Object::sym is under control. + # Keep OWNER[sym]. + @TOPLEVEL_ALIAS_TABLE[target][sym] = obj + replace_topalias(sym, obj) + replace_topobj(sym, obj) + + when nil + # New definition for sym + @TOPLEVEL_ALIAS_OWNER[sym] = target + @TOPLEVEL_ALIAS_TABLE[target][sym] = obj + replace_topalias(sym, obj) + replace_topobj(sym, obj) + + else # others + # An other widget set controls sym. + # Keep Object::sym (even if it is not defined) + # Keep ALIAS[sym]. + # Keep OWNER[sym]. + @TOPLEVEL_ALIAS_TABLE[target][sym] = obj + + end + end + + sym + end + private :set_topalias - # setup autoloads - @TOPLEVEL_ALIAS_TABLE[target].each{|sym, file| - Object.class_eval{remove_const sym} if Object.const_defined?(sym) - if file.kind_of?(String) - # file => autoload target file - Object.autoload(sym, file) + def __set_toplevel_aliases__(target, obj, *symbols) + # obj is a kind of String : define autoload path + # Class : use the class object + target = target.to_sym + symbols.each{|sym| set_topalias(target, obj, sym.to_sym)} + end + + def __set_loaded_toplevel_aliases__(autopath, target, obj, *symbols) + # autopath is an autoload file + # Currently, this method doesn't support that autoload loads + # different toplevels between <basename>.rb and <basename>.so extension. + shortpath = (autopath =~ /^(.*)(.rb|.so)$/)? $1: autopath + target = target.to_sym + symbols.map!{|sym| sym.to_sym} + + symbols.each{|sym| regist_sym_for_loaded_file(shortpath, obj, sym) } + symbols.each{|sym| set_topalias(target, obj, sym)} + end + + def backup_current_topdef(sym) + return if (current = @current_default_widget_set).nil? + + case @TOPLEVEL_ALIAS_OWNER[sym] + when false + # Object::sym is out of control. + if (cur_alias = topalias_defined?(sym)) && ! cur_alias.kind_of?(String) + @TOPLEVEL_ALIAS_TABLE[current][sym] = cur_alias + end + + when current + if cur_obj = topobj_defined?(sym) + if ! cur_obj.kind_of?(String) && (cur_alias = topalias_defined?(sym)) + if cur_alias.kind_of?(String) + # Mayby, user replaced Object::sym. + # Make Object::sym out of control. + @TOPLEVEL_ALIAS_OWNER[sym] = false + elsif cur_obj == cur_alias + # Possibley, defined normally. Backup it + @TOPLEVEL_ALIAS_TABLE[current][sym] = cur_alias + else + # Mayby, user replaced Object::sym. + # Make Object::sym out of control. + @TOPLEVEL_ALIAS_OWNER[sym] = false + end + end + else + # Mayby, user replaced Object::sym. + # Make Object::sym out of control. + @TOPLEVEL_ALIAS_OWNER[sym] = false + end + + when nil + # Object::sym is out of control. + if (cur_alias = topalias_defined?(sym)) && ! cur_alias.kind_of?(String) + # Possibley, defined normally. Backup it. + @TOPLEVEL_ALIAS_TABLE[current][sym] = cur_alias + end + else + # No authority to control Object::sym and ALIASES::sym. + # Do nothing. + end + end + private :backup_current_topdef + + def _replace_toplevel_aliases(target) + # backup + @TOPLEVEL_ALIAS_TABLE[target].each_key{|sym| + backup_current_topdef(sym) + } + + # replace + @TOPLEVEL_ALIAS_TABLE[target].each_key{|sym| + next if (obj = @TOPLEVEL_ALIAS_TABLE[target][sym]).nil? + if @TOPLEVEL_ALIAS_OWNER[sym] == false + # Object::sym is out of control. --> not change + # Keep OWNER[sym]. + replace_topalias(sym, obj) else - # file => loaded class object - Object.const_set(sym, file) + # New definition + @TOPLEVEL_ALIAS_OWNER[sym] = target + replace_topalias(sym, obj) + replace_topobj(sym, obj) end - @TOPLEVEL_ALIAS_OWNER[sym] = target } - # update current alias + # change default_widget_set @current_default_widget_set = target end + private :_replace_toplevel_aliases + + def __import_toplevel_aliases__(target, *symbols) + current = @current_default_widget_set + symbols.each{|sym| + sym = sym.to_sym + if (obj = @TOPLEVEL_ALIAS_TABLE[target][sym]).nil? + # remove + @TOPLEVEL_ALIAS_TABLE[current].delete(sym) + @TOPLEVEL_ALIAS_OWNER.delete(sym) + Tk::TOPLEVEL_ALIASES.module_eval{remove_const sym} if topalias_defined?(sym) + Object.class_eval{remove_const sym} if topobj_defined?(sym) + + elsif obj == false + # remove, but OWNER[sym] <- false and not treat Object::sym + @TOPLEVEL_ALIAS_TABLE[current].delete(sym) + @TOPLEVEL_ALIAS_OWNER[sym] = false + Tk::TOPLEVEL_ALIASES.module_eval{remove_const sym} if topalias_defined?(sym) + + elsif @TOPLEVEL_ALIAS_OWNER[sym] == false + # Object::sym is out of control. --> not change + # Keep OWNER[sym]. + @TOPLEVEL_ALIAS_TABLE[current][sym] = obj + replace_topalias(sym, obj) + + else + # new definition under control + @TOPLEVEL_ALIAS_OWNER[sym] = current + @TOPLEVEL_ALIAS_TABLE[current][sym] = obj + replace_topalias(sym, obj) + replace_topobj(sym, obj) + end + } + end + + def __remove_toplevel_aliases__(*symbols) + # remove toplevel aliases of current widget set + current = @current_default_widget_set + symbols.each{|sym| + sym = sym.to_sym + @TOPLEVEL_ALIAS_TABLE[current].delete(sym) + @TOPLEVEL_ALIAS_OWNER.delete(sym) + Tk::TOPLEVEL_ALIASES.module_eval{remove_const sym} if topalias_defined?(sym) + Object.class_eval{remove_const sym} if topobj_defined?(sym) + } + end + + def __reset_toplevel_owner__(*symbols) + symbols.each{|sym| @TOPLEVEL_ALIAS_OWNER.delete(sym.to_sym)} + end + + def __disable_toplevel_control__(*symbols) + symbols.each{|sym| @TOPLEVEL_ALIAS_OWNER[sym.to_sym] = false} + end + + def __create_widget_set__(new_set, src_set={}) + new_set = new_set.to_sym + if @TOPLEVEL_ALIAS_TABLE[new_set] + fail RuntimeError, "A widget-set #{new_set.inspect} is already exist." + end + if src_set.kind_of?(Symbol) + # new_set is an alias name of existed widget set. + @TOPLEVEL_ALIAS_TABLE[new_set] = @TOPLEVEL_ALIAS_TABLE[src_set] + else + @TOPLEVEL_ALIAS_TABLE[new_set] = {} + src_set.each{|sym, obj| set_topalias(new_set, obj, sym.to_sym) } + end + end end + ############################################ # setup default widget set => :Tk Tk.default_widget_set = :Tk |