diff options
220 files changed, 7100 insertions, 1265 deletions
@@ -1,3 +1,120 @@ +Wed Jun 11 05:55:31 2008 Hidetoshi NAGAI <[email protected]> + + * ext/tk/tcltklib.c: SEGV when tcltk-stubs is enabled. + + * ext/tk/tcltklib.c: avoid error on a shared object. + + * ext/tk/extconf.rb: support --with-tcltkversion + + * ext/tk/README.tcltklib: add document about --with-tcltkversion + + * ext/tk/lib/tk.rb, ext/tk/lib/multi-tk.rb, ext/tk/lib/remote-tk.rb: + not work on $SAFE==4 + + * ext/tk/lib/multi-tk.rb: Object#methods returns Symbols on Ruby1.9. + + * ext/tk/lib/tk/timer.rb: add TkTimer#at_end(proc) to register the + procedure which called at end of the timer. + + * ext/tk/lib/tk.rb, ext/tk/lib/tk/itemfont.rb, ext/tk/lib/font.rb: + support __IGNORE_UNKNOWN_CONFIGURE_OPTION__ about font options. + + * ext/tk/lib/*: treat __IGNORE_UNKNOWN_CONFIGURE_OPTION__ + + * ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb, + ext/tk/lib/tkextlib/iwidgets/scrolledlistbox.rb, + ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb: bug fix. + + * ext/tk/lib/tk/text.rb: typo. call a wrong method. + + * ext/tk/lib/tk/itemconfig.rb: ditto. + + * ext/tk/lib/tk.rb, ext/tk/lib/tk/itemconfig.rb, + ext/tk/lib/tk/canvas.rb: support alias names of option keys. + + * ext/tk/lib/tk/grid.rb: lack of module-method definitions. + + * ext/tk/lib/tk/pack.rb, ext/tk/lib/tk/grid.rb: increase supported + parameter patterns of configure method. + + * ext/tk/lib/tk.rb: add TkWindow#grid_anchor, grid_column, grid_row. + + * ext/tk/lib/tk/wm.rb: methods of Tk::Wm_for_General module cannot + pass the given block to methods of Tk::Wm module. + + * ext/tk/lib/tk/wm.rb: Wm#overrideredirect overwrites arguemnt to + an invalid value. + + * ext/tk/lib/tk.rb: fix memory (object) leak bug. + + * ext/tk/tcltklib.c, ext/tk/tkutil/tkutil.c: fix memory leak. + + * ext/tk/sample/demos-jp/aniwave.rb, ext/tk/sample/demos-en/aniwave.rb: + bug fix. + + * ext/tk/lib/tkextlib/blt/component.rb, + ext/tk/lib/tkextlib/tile/tentry.rb, + ext/tk/lib/tkextlib/tile/treeview.rb: ditto. + + * ext/tk/lib/tkextlib/tile/tpaned.rb: improve TPaned#add. + + * ext/tk/sample/demos-jp/widget, ext/tk/sample/demos-en/widget, + ext/tk/sample/demos-jp/style.rb, ext/tk/sample/demos-en/style.rb, + ext/tk/sample/demos-jp/bind.rb, ext/tk/sample/demos-en/bind.rb: + bug fix. + + * ext/tk/sample/ttk_wrapper.rb: ditto. + + * ext/tk/sample/ttk_wrapper.rb: support "if __FILE__ == $0" idiom. + + * ext/tk/sample/tktextio.rb: add binding for 'Ctrl-u' at console mode. + + * ext/tk/lib/tkextlib/tile.rb, ext/tk/lib/tkextlib/tile/style.rb, + ext/tk/sample/ttk_wrapper.rb: improve treating and control themes. + add Tk::Tile.themes and Tk::Tile.set_theme(theme). + + * ext/tk/lib/tkextlib/tile.rb: lack of autoload definitions. + + * ext/tk/lib/tkextlib/tile/tnotebook.rb: cannot use kanji (not UTF-8) + characters for headings. + + * ext/tk/lib/tkextlib/tkDND/shape.rb: wrong package name. + + * ext/tk/tkutil/tkutil.c: improve handling callback-subst-keys. + Now, support longnam-keys (e.g. '%CTT' on tkdnd-2.0; however, still + not support tkdnd-2.0 on tkextlib), and symbols of parameters (e.g. + :widget=>'%W', :keycode=>'%k', '%x'=>:x, '%X'=>:root_x, and so on; + those are attributes of event object). It means that Ruby/Tk accepts + not only "widget.bind(ev, '%W', '%k', ...){|w, k, ...| ... }", but + also "widget.bind(ev, :widget, :keycode, ...){|w, k, ...| ... }". + It is potentially incompatible, when user passes symbols to the + arguments of the callback block (the block receives the symbols as + strings). I think that is very rare case (probably, used by Ruby/Tk + experts only). When causes such trouble, please give strings instead + of such symbol parameters (e.g. call Symbol#to_s method). + + * ext/tk/lib/tk/event.rb, ext/tk/lib/tk/validation.rb, + ext/tk/lib/tkextlib/blt/treeview.rb, + ext/tk/lib/tkextlib/winico/winico.rb: ditto. + + * ext/tk/tkutil/tkutil.c: strings are available on subst_tables on + TkUtil::CallbackSubst class (it is useful on Ruby 1.9). + + * ext/tk/lib/tk/spinbox.rb, ext/tk/lib/tkextlib/iwidgets/hierarchy.rb, + ext/tk/lib/tkextlib/iwidgets/spinner.rb, + ext/tk/lib/tkextlib/iwidgets/entryfield.rb, + ext/tk/lib/tkextlib/iwidgets/calendar.rb, + ext/tk/lib/tkextlib/blt/dragdrop.rb, + ext/tk/lib/tkextlib/tkDND/tkdnd.rb, + ext/tk/lib/tkextlib/treectrl/tktreectrl.rb, + ext/tk/lib/tkextlib/tktable/tktable.rb: disable code piece became + unnecessary by reason of the changes of ext/tk/tkutil/tkutil.c. + + * ext/tk/lib/tk.rb, ext/tk/lib/multi-tk.rb: change strategy to define + the constant WITH_ENCODING. + + * ext/tk/lib/tk.rb: fix bug on Tk::Encoding.tk_encoding_names. + Wed Jun 11 03:40:37 2008 Akinori MUSHA <[email protected]> * lib/find.rb (Find#find): Return an enumerator if no block is diff --git a/ext/tk/ChangeLog.tkextlib b/ext/tk/ChangeLog.tkextlib index 359b466a32..8c5d01a954 100644 --- a/ext/tk/ChangeLog.tkextlib +++ b/ext/tk/ChangeLog.tkextlib @@ -1,3 +1,9 @@ +2008-05-12 Hidetoshi NAGAI <[email protected]> + + * ext/tk/lib/tkextlib/tkDND/shape.rb: wrong package name. + +--------------< ... some changes ... >------------------ + 2007-05-26 Hidetoshi NAGAI <[email protected]> * ext/tk/lib/tkextlib/tcllib/tablelist.rb: fix typo. diff --git a/ext/tk/README.tcltklib b/ext/tk/README.tcltklib index b94d778104..8c6dd5178f 100644 --- a/ext/tk/README.tcltklib +++ b/ext/tk/README.tcltklib @@ -5,10 +5,14 @@ Tcl/Tk libraries or header files are installed but are not found, you can give the information by arguments of the 'configure' script. Please give some or all of the following options. + --with-tcltkversion=<version> + force version of Tcl/Tk libaray + (e.g. libtcl8.4g.so ==> --with-tcltkversion=8.4g) + --with-tcllib=<libname> (e.g. libtcl8.4.so ==> --with-tcllib=tcl8.4) --with-tklib=<libname> (e.g. libtk8.4.so ==> --with-tklib=tk8.4) - --enable-tcltk_stubs (if you force to enable stubs) + --enable-tcltk-stubs (if you force to enable stubs) --with-tcl-dir=<path> equal to "--with-tcl-include=<path>/include --with-tcl-lib=<path>/lib" diff --git a/ext/tk/extconf.rb b/ext/tk/extconf.rb index cb7621fbd4..4807ea7b40 100644 --- a/ext/tk/extconf.rb +++ b/ext/tk/extconf.rb @@ -48,15 +48,60 @@ tk_ldir2 = with_config("tk-lib") tcl_ldir2 = with_config("tcl-lib") x11_ldir2 = with_config("X11-lib") +tk_ldir_list = [tk_ldir2, tk_ldir] +tcl_ldir_list = [tcl_ldir2, tcl_ldir] + tklib = with_config("tklib") tcllib = with_config("tcllib") stubs = enable_config("tcltk_stubs") || with_config("tcltk_stubs") +tcltk_version = with_config("tcltkversion") + use_X = with_config("X11", (! is_win32)) -def find_tcl(tcllib, stubs, *opt_paths) +def check_tcltk_version(version) + return [nil, nil] unless version + + version = version.strip + + tclver = version.dup + tkver = version.dup + + major = dot = minor = dot = plvl = ext = nil + + if version =~ /^(\d)(\.?)(\d)(\.?)(\d*)(.*)$/ + major = $1; minor_dot = $2; minor = $3; plvl_dot = $4; plvl = $5; ext = $6 + dot = ! minor_dot.empty? + if plvl_dot.empty? && ! plvl.empty? + minor << plvl + end + elsif version =~ /^(\d)(\.?)(\d?)(.*)$/ + major = $1; minor_dot = $2; minor = $3; ext = $4 + dot = ! minor_dot.empty? + else # unknown -> believe user + return [tclver, tkver] + end + + # check Tcl7.6 / Tk4.2 ? + if major == "7" # Tcl7.6 ( not support Tclversion < 7.6 ) + # Tk4.2 + tkver = "4" + ((dot)? ".": "") + ((minor.empty)? "": "2") + ext + elsif major == "4" # Tk4.2 ( not support Tkversion < 4.2 ) + # Tcl7.6 + tclver = "7" + ((dot)? ".": "") + ((minor.empty)? "": "6") + ext + end + + [tclver, tkver] +end + +def find_tcl(tcllib, stubs, version, *opt_paths) default_paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"] - paths = opt_paths.compact.concat(default_paths) + default_paths << "/Tcl/lib" # default for ActiveTcl + + if (paths = opt_paths.compact).empty? + paths = default_paths + end + if stubs func = "Tcl_InitStubs" lib = "tclstub" @@ -64,25 +109,42 @@ def find_tcl(tcllib, stubs, *opt_paths) func = "Tcl_FindExecutable" lib = "tcl" end + + if version && ! version.empty? + versions = [version] + else + versions = %w[8.6 8.5 8.4 8.3 8.2 8.1 8.0 7.6] + end + if tcllib - find_library(tcllib, func, *paths) + st = find_library(tcllib, func, *paths) else - %w[8.6 8.5 8.4 8.3 8.2 8.1 8.0 7.6].find { |ver| - find_library("#{lib}#{ver}", func, *paths) or - find_library("#{lib}#{ver.delete('.')}", func, *paths) or - find_library("#{lib}#{ver}g", func, *paths) or - find_library("#{lib}#{ver.delete('.')}g", func, *paths) or - find_library("tcl#{ver}", func, *paths) or - find_library("tcl#{ver.delete('.')}", func, *paths) or - find_library("tcl#{ver}g", func, *paths) or - find_library("tcl#{ver.delete('.')}g", func, *paths) - } || find_library(lib, func, *paths) + st = versions.find { |ver| + find_library("#{lib}#{ver}", func, *paths) or + find_library("#{lib}#{ver.delete('.')}", func, *paths) or + find_library("#{lib}#{ver}g", func, *paths) or + find_library("#{lib}#{ver.delete('.')}g", func, *paths) or + find_library("tcl#{ver}", func, *paths) or + find_library("tcl#{ver.delete('.')}", func, *paths) or + find_library("tcl#{ver}g", func, *paths) or + find_library("tcl#{ver.delete('.')}g", func, *paths) + } || (!version && find_library(lib, func, *paths)) + end + + unless st + puts("Warning:: cannot find Tcl library. tcltklib will not be compiled (tcltklib is disabled on your Ruby == Ruby/Tk will not work). Please check configure options.") end + st end -def find_tk(tklib, stubs, *opt_paths) +def find_tk(tklib, stubs, version, *opt_paths) default_paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"] - paths = opt_paths.compact.concat(default_paths) + default_paths << "/Tcl/lib" # default for ActiveTcl + + if (paths = opt_paths.compact).empty? + paths = default_paths + end + if stubs func = "Tk_InitStubs" lib = "tkstub" @@ -90,27 +152,43 @@ def find_tk(tklib, stubs, *opt_paths) func = "Tk_Init" lib = "tk" end + + if version && ! version.empty? + versions = [version] + else + versions = %w[8.6 8.5 8.4 8.3 8.2 8.1 8.0 4.2] + end + if tklib - find_library(tklib, func, *paths) + st = find_library(tklib, func, *paths) else - %w[8.6 8.5 8.4 8.3 8.2 8.1 8.0 4.2].find { |ver| - find_library("#{lib}#{ver}", func, *paths) or - find_library("#{lib}#{ver.delete('.')}", func, *paths) or - find_library("#{lib}#{ver}g", func, *paths) or - find_library("#{lib}#{ver.delete('.')}g", func, *paths) or - find_library("tk#{ver}", func, *paths) or - find_library("tk#{ver.delete('.')}", func, *paths) or - find_library("tk#{ver}g", func, *paths) or - find_library("tk#{ver.delete('.')}g", func, *paths) - } || find_library(lib, func, *paths) + st = versions.find { |ver| + find_library("#{lib}#{ver}", func, *paths) or + find_library("#{lib}#{ver.delete('.')}", func, *paths) or + find_library("#{lib}#{ver}g", func, *paths) or + find_library("#{lib}#{ver.delete('.')}g", func, *paths) or + find_library("tk#{ver}", func, *paths) or + find_library("tk#{ver.delete('.')}", func, *paths) or + find_library("tk#{ver}g", func, *paths) or + find_library("tk#{ver.delete('.')}g", func, *paths) + } || (!version && find_library(lib, func, *paths)) end + + unless st + puts("Warning:: cannot find Tk library. tcltklib will not be compiled (tcltklib is disabled on your Ruby == Ruby/Tk will not work). Please check configure options.") + end + st end def find_X11(*opt_paths) default_paths = [ "/usr/X11/lib", "/usr/lib/X11", "/usr/X11R6/lib", "/usr/openwin/lib" ] paths = opt_paths.compact.concat(default_paths) - find_library("X11", "XOpenDisplay", *paths) + st = find_library("X11", "XOpenDisplay", *paths) + unless st + puts("Warning:: cannot find X11 library. tcltklib will not be compiled (tcltklib is disabled on your Ruby == Ruby/Tk will not work). Please check configure options. If your Tcl/Tk don't require X11, please try --without-X11.") + end + st end def pthread_check() @@ -291,11 +369,13 @@ EOF end end -if have_header("tcl.h") && have_header("tk.h") && +tclver, tkver = check_tcltk_version(tcltk_version) + +if have_header("tcl.h") && have_header("tk.h") && ( tcltk_framework || ( ( !use_X || find_X11(x11_ldir2, x11_ldir) ) && - find_tcl(tcllib, stubs, tcl_ldir2, tcl_ldir) && - find_tk(tklib, stubs, tk_ldir2, tk_ldir) ) ) + find_tcl(tcllib, stubs, tclver, *tcl_ldir_list) && + find_tk(tklib, stubs, tkver, *tk_ldir_list) ) ) $CPPFLAGS += ' -DUSE_TCL_STUBS -DUSE_TK_STUBS' if stubs $CPPFLAGS += ' -D_WIN32' if /cygwin/ =~ RUBY_PLATFORM @@ -322,6 +402,8 @@ if have_header("tcl.h") && have_header("tk.h") && $INSTALLFILES ||= [] $INSTALLFILES << ["lib/tkextlib/SUPPORT_STATUS", "$(RUBYLIBDIR)", "lib"] + have_func("rb_hash_lookup", "ruby.h") + # create $defs << %[-DRUBY_VERSION=\\"#{RUBY_VERSION}\\"] $defs << %[-DRUBY_RELEASE_DATE=\\"#{RUBY_RELEASE_DATE}\\"] diff --git a/ext/tk/lib/multi-tk.rb b/ext/tk/lib/multi-tk.rb index fd9a863888..4f39874d30 100644 --- a/ext/tk/lib/multi-tk.rb +++ b/ext/tk/lib/multi-tk.rb @@ -28,7 +28,13 @@ class << TclTkIp if Thread.current.group != ThreadGroup::Default raise SecurityError, 'only ThreadGroup::Default can call TclTkIp.new' end - __new__(*args) + obj = __new__(*args) + obj.instance_eval{ + @force_default_encoding ||= [false].taint + @encoding ||= [nil].taint + def @encoding.to_s; self.join(nil); end + } + obj end end @@ -115,7 +121,8 @@ class MultiTkIp BASE_DIR = File.dirname(__FILE__) WITH_RUBY_VM = Object.const_defined?(:VM) && ::VM.class == Class - WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class + WITH_ENCODING = defined?(::Encoding.default_external) + #WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class (@@SLAVE_IP_ID = ['slave'.freeze, '0'.taint]).instance_eval{ @mutex = Mutex.new @@ -226,8 +233,8 @@ class MultiTkIp def call(*args) unless @ip.deleted? current = Thread.current - backup_ip = current['callback_ip'] - current['callback_ip'] = @ip + backup_ip = current[:callback_ip] + current[:callback_ip] = @ip begin ret = @ip.cb_eval(@cmd, *args) fail ret if ret.kind_of?(Exception) @@ -260,7 +267,7 @@ class MultiTkIp fail e end ensure - current['callback_ip'] = backup_ip + current[:callback_ip] = backup_ip end end end @@ -753,14 +760,23 @@ class MultiTkIp current[:mutex] = mutex = Mutex.new current[:root_check] = cond_var = ConditionVariable.new + status = [nil] + def status.value + self[0] + end + def status.value=(val) + self[0] = val + end + current[:status] = status + begin - current[:status] = interp.mainloop(true) + current[:status].value = interp.mainloop(true) rescue Exception=>e - current[:status] = e + current[:status].value = e ensure mutex.synchronize{ cond_var.broadcast } end - current[:status] = interp.mainloop(false) + current[:status].value = interp.mainloop(false) } until @interp_thread[:interp] Thread.pass @@ -778,6 +794,12 @@ class MultiTkIp end end + @interp.instance_eval{ + @force_default_encoding ||= [false].taint + @encoding ||= [nil].taint + def @encoding.to_s; self.join(nil); end + } + @ip_name = nil @callback_status = [].taint @@ -951,8 +973,9 @@ class MultiTkIp begin class << subclass self.methods.each{|m| + name = m.to_s begin - unless m == '__id__' || m == '__send__' || m == 'freeze' + unless name == '__id__' || name == '__send__' || name == 'freeze' undef_method(m) end rescue Exception @@ -1157,6 +1180,11 @@ class MultiTkIp # safe interpreter ip_name = _create_slave_ip_name slave_ip = @interp.create_slave(ip_name, true) + slave_ip.instance_eval{ + @force_default_encoding ||= [false].taint + @encoding ||= [nil].taint + def @encoding.to_s; self.join(nil); end + } @slave_ip_tbl[ip_name] = slave_ip def slave_ip.safe_base? true @@ -1199,6 +1227,11 @@ class MultiTkIp ip_name = _create_slave_ip_name slave_ip = @interp.create_slave(ip_name, false) + slave_ip.instance_eval{ + @force_default_encoding ||= [false].taint + @encoding ||= [nil].taint + def @encoding.to_s; self.join(nil); end + } slave_ip._invoke('set', 'argv0', name) if name.kind_of?(String) slave_ip._invoke('set', 'argv', _keys2opts(keys)) @interp._invoke('load', '', 'Tk', ip_name) @@ -1268,9 +1301,21 @@ class MultiTkIp # create master-ip unless WITH_RUBY_VM @interp = TclTkIp.new(name, _keys2opts(tk_opts)) + @interp.instance_eval{ + @force_default_encoding ||= [false].taint + @encoding ||= [nil].taint + def @encoding.to_s; self.join(nil); end + } + else ### Ruby 1.9 !!!!!!!!!!! @interp_thread = Thread.new{ Thread.current[:interp] = interp = TclTkIp.new(name, _keys2opts(tk_opts)) + interp.instance_eval{ + @force_default_encoding ||= [false].taint + @encoding ||= [nil].taint + def @encoding.to_s; self.join(nil); end + } + #sleep TclTkLib.mainloop(true) } @@ -1400,8 +1445,8 @@ class MultiTkIp def self.__getip current = Thread.current - if TclTkLib.mainloop_thread? != false && current['callback_ip'] - return current['callback_ip'] + if TclTkLib.mainloop_thread? != false && current[:callback_ip] + return current[:callback_ip] end if current.group == ThreadGroup::Default @@DEFAULT_MASTER @@ -1993,12 +2038,12 @@ class MultiTkIp cmd = args.shift end current = Thread.current - backup_ip = current['callback_ip'] - current['callback_ip'] = self + backup_ip = current[:callback_ip] + current[:callback_ip] = self begin eval_proc_core(false, cmd, *args) ensure - current['callback_ip'] = backup_ip + current[:callback_ip] = backup_ip end end @@ -2016,8 +2061,8 @@ class MultiTkIp if TclTkLib.mainloop_thread? == true # call from eventloop current = Thread.current - backup_ip = current['callback_ip'] - current['callback_ip'] = self + backup_ip = current[:callback_ip] + current[:callback_ip] = self begin eval_proc_core(false, proc{|safe, *params| @@ -2025,7 +2070,7 @@ class MultiTkIp cmd.call(*params) }, *args) ensure - current['callback_ip'] = backup_ip + current[:callback_ip] = backup_ip end else eval_proc_core(true, @@ -2170,6 +2215,10 @@ end # event loop # all master/slave IPs are controled by only one event-loop class << MultiTkIp + def default_master? + __getip == @@DEFAULT_MASTER + end + def mainloop(check_root = true) __getip.mainloop(check_root) end @@ -2431,7 +2480,7 @@ class MultiTkIp def mainloop(check_root = true, restart_on_dead = true) raise SecurityError, "no permission to manipulate" unless self.manipulable? - unless WITH_RUBY_VM ### Ruby 1.9 !!!!!!!!!!! + if WITH_RUBY_VM ### Ruby 1.9 !!!!!!!!!!! return @interp_thread.value if @interp_thread end @@ -3289,6 +3338,42 @@ class << MultiTkIp def encoding_table __getip.encoding_table end + + def force_default_encoding=(mode) + __getip.force_default_encoding=(mode) + end + + def force_default_encoding? + __getip.force_default_encoding? + end + + def default_encoding=(enc) + __getip.default_encoding=(enc) + end + + def encoding=(enc) + __getip.encoding=(enc) + end + + def encoding_name + __getip.encoding_name + end + + def encoding_obj + __getip.encoding_obj + end + alias encoding encoding_name + alias default_encoding encoding_name + + def encoding_convertfrom(str, enc=None) + __getip.encoding_convertfrom(str, enc) + end + alias encoding_convert_from encoding_convertfrom + + def encoding_convertto(str, enc=None) + __getip.encoding_convertto(str, enc) + end + alias encoding_convert_to encoding_convertto end class MultiTkIp def encoding_table @@ -3339,6 +3424,7 @@ end # remove methods for security +=begin class MultiTkIp INTERP_THREAD = @@DEFAULT_MASTER.instance_variable_get('@interp_thread') INTERP_MUTEX = INTERP_THREAD[:mutex] @@ -3362,6 +3448,34 @@ class MultiTkIp remove_const(:INTERP_MUTEX) remove_const(:INTERP_ROOT_CHECK) end +=end +if MultiTkIp::WITH_RUBY_VM && + ! MultiTkIp::RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!! + class MultiTkIp + INTERP_THREAD = @@DEFAULT_MASTER.instance_variable_get('@interp_thread') + INTERP_THREAD_STATUS = INTERP_THREAD[:status] + INTERP_MUTEX = INTERP_THREAD[:mutex] + INTERP_ROOT_CHECK = INTERP_THREAD[:root_check] + end + module TkCore + INTERP_THREAD = MultiTkIp::INTERP_THREAD + INTERP_THREAD_STATUS = MultiTkIp::INTERP_THREAD_STATUS + INTERP_MUTEX = MultiTkIp::INTERP_MUTEX + INTERP_ROOT_CHECK = MultiTkIp::INTERP_ROOT_CHECK + end + class MultiTkIp + remove_const(:INTERP_THREAD) + remove_const(:INTERP_THREAD_STATUS) + remove_const(:INTERP_MUTEX) + remove_const(:INTERP_ROOT_CHECK) + end +end + +class MultiTkIp + # undef_method :instance_eval + undef_method :instance_variable_get + undef_method :instance_variable_set +end # end of MultiTkIp definition # defend against modification diff --git a/ext/tk/lib/remote-tk.rb b/ext/tk/lib/remote-tk.rb index 70115a60aa..f267900d53 100644 --- a/ext/tk/lib/remote-tk.rb +++ b/ext/tk/lib/remote-tk.rb @@ -88,6 +88,10 @@ class RemoteTkIp @slave_ip_tbl = {} @slave_ip_top = {} + @force_default_encoding ||= [false].taint + @encoding ||= [nil].taint + def @encoding.to_s; self.join(nil); end + @tk_windows.taint unless @tk_windows.tainted? @tk_table_list.taint unless @tk_table_list.tainted? @slave_ip_tbl.taint unless @slave_ip_tbl.tainted? diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb index 0d00ecf207..88e47626f5 100644 --- a/ext/tk/lib/tk.rb +++ b/ext/tk/lib/tk.rb @@ -21,6 +21,17 @@ class TclTkIp # for RemoteTkIp '' end + + alias __initialize__ initialize + private :__initialize__ + + def initialize(*args) + __initialize__(*args) + + @force_default_encoding ||= [false].taint + @encoding ||= [nil].taint + def @encoding.to_s; self.join(nil); end + end end # define TkComm module (step 1: basic functions) @@ -775,7 +786,7 @@ end private :_curr_cmd_id, :_next_cmd_id module_function :_curr_cmd_id, :_next_cmd_id - def install_cmd(cmd) + def TkComm.install_cmd(cmd, local_cmdtbl=nil) return '' if cmd == '' begin ns = TkCore::INTERP._invoke_without_enc('namespace', 'current') @@ -794,6 +805,15 @@ end @cmdtbl = [] unless defined? @cmdtbl @cmdtbl.taint unless @cmdtbl.tainted? @cmdtbl.push id + + if local_cmdtbl && local_cmdtbl.kind_of?(Array) + begin + local_cmdtbl << id + rescue Exception + # ignore + end + end + #return Kernel.format("rb_out %s", id); if ns 'rb_out' << TkCore::INTERP._ip_id_ << ' ' << ns << ' ' << id @@ -801,14 +821,30 @@ end 'rb_out' << TkCore::INTERP._ip_id_ << ' ' << id end end - def uninstall_cmd(id) + def TkComm.uninstall_cmd(id, local_cmdtbl=nil) #id = $1 if /rb_out\S* (c(_\d+_)?\d+)/ =~ id id = $4 if id =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/ + + if local_cmdtbl && local_cmdtbl.kind_of?(Array) + begin + local_cmdtbl.delete(id) + rescue Exception + # ignore + end + end + @cmdtbl.delete(id) + #Tk_CMDTBL.delete(id) TkCore::INTERP.tk_cmd_tbl.delete(id) end # private :install_cmd, :uninstall_cmd - module_function :install_cmd, :uninstall_cmd + # module_function :install_cmd, :uninstall_cmd + def install_cmd(cmd) + TkComm.install_cmd(cmd, @cmdtbl) + end + def uninstall_cmd(id) + TkComm.uninstall_cmd(id, @cmdtbl) + end =begin def install_win(ppath,name=nil) @@ -1074,7 +1110,8 @@ module TkCore extend TkComm WITH_RUBY_VM = Object.const_defined?(:VM) && ::VM.class == Class - WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class + WITH_ENCODING = defined?(::Encoding.default_external) + #WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD ### Ruby 1.9 !!!!!!!!!!!!!!!!!!!!!!!!!! @@ -1110,17 +1147,26 @@ module TkCore Thread.current[:interp] = e raise e end - Thread.current[:status] = nil + + status = [nil] + def status.value + self[0] + end + def status.value=(val) + self[0] = val + end + + Thread.current[:status] = status #sleep begin - Thread.current[:status] = TclTkLib.mainloop(true) + Thread.current[:status].value = TclTkLib.mainloop(true) rescue Exception=>e - Thread.current[:status] = e + Thread.current[:status].value = e ensure INTERP_MUTEX.synchronize{ INTERP_ROOT_CHECK.broadcast } end - Thread.current[:status] = TclTkLib.mainloop(false) + Thread.current[:status].value = TclTkLib.mainloop(false) } until INTERP_THREAD[:interp] @@ -1130,11 +1176,15 @@ module TkCore raise INTERP_THREAD[:interp] if INTERP_THREAD[:interp].kind_of? Exception INTERP = INTERP_THREAD[:interp] + INTERP_THREAD_STATUS = INTERP_THREAD[:status] end def INTERP.__getip self end + def INTERP.default_master? + true + end INTERP.instance_eval{ # @tk_cmd_tbl = {}.taint @@ -1155,6 +1205,10 @@ module TkCore @init_ip_env = [].taint # table of Procs @add_tk_procs = [].taint # table of [name, args, body] + @force_default_encoding ||= [false].taint + @encoding ||= [nil].taint + def @encoding.to_s; self.join(nil); end + @cb_entry_class = Class.new(TkCallbackEntry){ class << self def inspect @@ -1273,7 +1327,7 @@ module TkCore }) << ' %W') INTERP.add_tk_procs(TclTkLib::FINALIZE_PROC_NAME, '', - "bind all <#{WIDGET_DESTROY_HOOK}> {}") + "catch { bind all <#{WIDGET_DESTROY_HOOK}> {} }") INTERP.add_tk_procs('rb_out', 'ns args', <<-'EOL') if [regexp {^::} $ns] { @@ -1441,7 +1495,9 @@ module TkCore def after(ms, cmd=Proc.new) cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret}) - tk_call_without_enc("after",ms,cmdid) # return id + after_id = tk_call_without_enc("after",ms,cmdid) + after_id.instance_variable_set('@cmdid', cmdid) + after_id end =begin def after(ms, cmd=Proc.new) @@ -1471,7 +1527,9 @@ module TkCore def after_idle(cmd=Proc.new) cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret}) - tk_call_without_enc('after','idle',cmdid) + after_id = tk_call_without_enc('after','idle',cmdid) + after_id.instance_variable_set('@cmdid', cmdid) + after_id end =begin def after_idle(cmd=Proc.new) @@ -1489,6 +1547,11 @@ module TkCore def after_cancel(afterId) tk_call_without_enc('after','cancel',afterId) + if (cmdid = afterId.instance_variable_get('@cmdid')) + afterId.instance_variable_set('@cmdid', nil) + uninstall_cmd(cmdid) + end + afterId end def windowingsystem @@ -1611,14 +1674,19 @@ module TkCore if !TkCore::WITH_RUBY_VM || TkCore::RUN_EVENTLOOP_ON_MAIN_THREAD TclTkLib.mainloop(check_root) else ### Ruby 1.9 !!!!! + unless TkCore::INTERP.default_master? + # [MultiTkIp] slave interp ? + return TkCore::INTERP._thread_tkwait('window', '.') if check_root + end + begin TclTkLib.set_eventloop_window_mode(true) if check_root INTERP_MUTEX.synchronize{ INTERP_ROOT_CHECK.wait(INTERP_MUTEX) - status = INTERP_THREAD[:status] - if status - INTERP_THREAD[:status] = nil + status = INTERP_THREAD_STATUS.value + if status && TkCore::INTERP.default_master? + INTERP_THREAD_STATUS.value = nil if $SAFE < 4 raise status if status.kind_of?(Exception) end } @@ -2458,7 +2526,8 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) alias default_encoding encoding_name def tk_encoding_names - TkComm.simplelist(TkCore::INTERP._invoke_without_enc(Tk::Encoding::ENCNAMES_CMD[0], Tk::Encoding::ENCNAMES_CMD[1])) + #TkComm.simplelist(TkCore::INTERP._invoke_without_enc(Tk::Encoding::ENCNAMES_CMD[0], Tk::Encoding::ENCNAMES_CMD[1])) + TkComm.simplelist(TkCore::INTERP._invoke_without_enc('encoding', 'names')) end def encoding_names self.tk_encoding_names.find_all{|name| @@ -2592,16 +2661,16 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) class TclTkIp def force_default_encoding=(mode) - @force_default_encoding = (mode)? true: false + @force_default_encoding[0] = (mode)? true: false end def force_default_encoding? - @force_default_encoding ||= false + @force_default_encoding[0] ||= false end def default_encoding=(name) - name = name.name if name.kind_of?(::Encoding) if Tk::WITH_ENCODING - @encoding = name + name = name.name if Tk::WITH_ENCODING && name.kind_of?(::Encoding) + @encoding[0] = name.to_s.dup end # from tkencoding.rb by [email protected] @@ -2612,16 +2681,16 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) end def encoding_name - (@encoding)? @encoding.dup: nil + (@encoding[0])? @encoding[0].dup: nil end alias encoding encoding_name alias default_encoding encoding_name def encoding_obj if Tk::WITH_ENCODING - Tk::Encoding.tcl2rb_encoding(@encoding) + Tk::Encoding.tcl2rb_encoding(@encoding[0]) else - (@encoding)? @encoding.dup: nil + (@encoding[0])? @encoding[0].dup: nil end end @@ -3211,7 +3280,15 @@ module TkTreatFont next else fnt = hash_kv(fnt) if fnt.kind_of?(Hash) - tk_call(*(__config_cmd << "-#{optkey}" << fnt)) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + tk_call(*(__config_cmd << "-#{optkey}" << fnt)) + else + begin + tk_call(*(__config_cmd << "-#{optkey}" << fnt)) + rescue + # ignore + end + end end end next @@ -3265,7 +3342,15 @@ module TkTreatFont fobj = fontobj # create a new TkFont object else ltn = hash_kv(ltn) if ltn.kind_of?(Hash) - tk_call(*(__config_cmd << "-#{optkey}" << ltn)) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + tk_call(*(__config_cmd << "-#{optkey}" << ltn)) + else + begin + tk_call(*(__config_cmd << "-#{optkey}" << ltn)) + rescue => e + # ignore + end + end next end @@ -3317,7 +3402,15 @@ module TkTreatFont fobj = fontobj # create a new TkFont object else knj = hash_kv(knj) if knj.kind_of?(Hash) - tk_call(*(__config_cmd << "-#{optkey}" << knj)) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + tk_call(*(__config_cmd << "-#{optkey}" << knj)) + else + begin + tk_call(*(__config_cmd << "-#{optkey}" << knj)) + rescue => e + # ignore + end + end next end @@ -3447,6 +3540,11 @@ module TkConfigMethod end private :__configinfo_struct + def __optkey_aliases + {} + end + private :__optkey_aliases + def __numval_optkeys [] end @@ -3561,6 +3659,11 @@ module TkConfigMethod fail ArgumentError, "Invalid option `#{orig_slot.inspect}'" end + alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot} + if real_name + slot = real_name.to_s + end + if ( method = _symbolkey2str(__val2ruby_optkeys())[slot] ) optval = tk_call_without_enc(*(__cget_cmd << "-#{slot}")) begin @@ -3635,14 +3738,35 @@ module TkConfigMethod unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ __cget_core(slot) else - __cget_core(slot) rescue nil + begin + __cget_core(slot) + rescue => e + if current_configinfo.has_key?(slot.to_s) + # error on known option + fail e + else + # unknown option + nil + end + end end end + def cget_strict(slot) + # never use TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + __cget_core(slot) + end def __configure_core(slot, value=None) if slot.kind_of? Hash slot = _symbolkey2str(slot) + __optkey_aliases.each{|alias_name, real_name| + alias_name = alias_name.to_s + if slot.has_key?(alias_name) + slot[real_name.to_s] = slot.delete(alias_name) + end + } + __methodcall_optkeys.each{|key, method| value = slot.delete(key.to_s) self.__send__(method, value) if value @@ -3679,6 +3803,11 @@ module TkConfigMethod fail ArgumentError, "Invalid option `#{orig_slot.inspect}'" end + alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot} + if real_name + slot = real_name.to_s + end + if ( conf = __keyonly_optkeys.find{|k, v| k.to_s == slot} ) defkey, undefkey = conf if value @@ -3730,7 +3859,17 @@ module TkConfigMethod __configure_core(slot) unless slot.empty? end else - __configure_core(slot, value) rescue nil + begin + __configure_core(slot, value) + rescue => e + if current_configinfo.has_key?(slot.to_s) + # error on known option + fail e + else + # unknown option + nil + end + end end end self @@ -3766,6 +3905,12 @@ module TkConfigMethod else if slot slot = slot.to_s + + alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot} + if real_name + slot = real_name.to_s + end + case slot when /^(#{__val2ruby_optkeys().keys.join('|')})$/ method = _symbolkey2str(__val2ruby_optkeys())[slot] @@ -4139,6 +4284,12 @@ module TkConfigMethod else if slot slot = slot.to_s + + alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot} + if real_name + slot = real_name.to_s + end + case slot when /^(#{__val2ruby_optkeys().keys.join('|')})$/ method = _symbolkey2str(__val2ruby_optkeys())[slot] @@ -4734,6 +4885,13 @@ class TkWindow<TkObject fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey) } + __optkey_aliases.each{|alias_name, real_name| + alias_name = alias_name.to_s + if keys.has_key?(alias_name) + keys[real_name.to_s] = keys.delete(alias_name) + end + } + __methodcall_optkeys.each{|key| key = key.to_s methodkeys[key] = keys.delete(key) if keys.key?(key) @@ -4771,12 +4929,25 @@ class TkWindow<TkObject else begin tk_call_without_enc(cmd, @path, *hash_kv(keys, true)) - rescue + rescue => e tk_call_without_enc(cmd, @path) keys = __check_available_configure_options(keys) unless keys.empty? - tk_call_without_enc('destroy', @path) - tk_call_without_enc(cmd, @path, *hash_kv(keys, true)) + begin + # try to configure + configure(keys) + rescue + # fail => includes options adaptable when creattion only? + begin + tk_call_without_enc('destroy', @path) + rescue + # cannot rescue options error + fail e + else + # re-create widget + tk_call_without_enc(cmd, @path, *hash_kv(keys, true)) + end + end end end end @@ -4916,6 +5087,15 @@ class TkWindow<TkObject self end + def grid_anchor(anchor=None) + if anchor == None + TkGrid.anchor(self) + else + TkGrid.anchor(self, anchor) + self + end + end + def grid_forget #tk_call('grid', 'forget', epath) TkGrid.forget(self) @@ -4947,12 +5127,14 @@ class TkWindow<TkObject TkGrid.columnconfigure(self, index, keys) end alias grid_columnconfigure grid_columnconfig + alias grid_column grid_columnconfig def grid_rowconfig(index, keys) #tk_call('grid', 'rowconfigure', epath, index, *hash_kv(keys)) TkGrid.rowconfigure(self, index, keys) end alias grid_rowconfigure grid_rowconfig + alias grid_row grid_rowconfig def grid_columnconfiginfo(index, slot=nil) #if slot @@ -5195,11 +5377,13 @@ class TkWindow<TkObject end children.each{|path, obj| - if defined?(@cmdtbl) - for id in @cmdtbl - uninstall_cmd id + obj.instance_eval{ + if defined?(@cmdtbl) + for id in @cmdtbl + uninstall_cmd id + end end - end + } TkCore::INTERP.tk_windows.delete(path) } @@ -5317,7 +5501,7 @@ TkWidget = TkWindow #Tk.freeze module Tk - RELEASE_DATE = '2008-03-29'.freeze + RELEASE_DATE = '2008-06-11'.freeze autoload :AUTO_PATH, 'tk/variable' autoload :TCL_PACKAGE_PATH, 'tk/variable' diff --git a/ext/tk/lib/tk/canvas.rb b/ext/tk/lib/tk/canvas.rb index fceadd5e9c..36ea008a17 100644 --- a/ext/tk/lib/tk/canvas.rb +++ b/ext/tk/lib/tk/canvas.rb @@ -168,6 +168,8 @@ class Tk::Canvas<TkWindow #tk_tcl2ruby(tk_send_without_enc('canvasy', screen_y, *args)) number(tk_send_without_enc('canvasy', screen_y, *args)) end + alias canvas_x canvasx + alias canvas_y canvasy def coords(tag, *args) if args == [] @@ -642,6 +644,13 @@ class TkcItem<TkObject fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey) } + __item_optkey_aliases(nil).each{|alias_name, real_name| + alias_name = alias_name.to_s + if keys.has_key?(alias_name) + keys[real_name.to_s] = keys.delete(alias_name) + end + } + __item_methodcall_optkeys(nil).each{|key| key = key.to_s methodkeys[key] = keys.delete(key) if keys.key?(key) diff --git a/ext/tk/lib/tk/canvastag.rb b/ext/tk/lib/tk/canvastag.rb index 7feea1575c..49796d80b2 100644 --- a/ext/tk/lib/tk/canvastag.rb +++ b/ext/tk/lib/tk/canvastag.rb @@ -63,6 +63,9 @@ module TkcTagAccess def cget(option) @c.itemcget(@id, option) end + def cget_strict(option) + @c.itemcget_strict(@id, option) + end def configure(key, value=None) @c.itemconfigure(@id, key, value) diff --git a/ext/tk/lib/tk/composite.rb b/ext/tk/lib/tk/composite.rb index 728b02f608..883d43c3ea 100644 --- a/ext/tk/lib/tk/composite.rb +++ b/ext/tk/lib/tk/composite.rb @@ -181,6 +181,57 @@ module TkComposite delegate_alias(option, option, *wins) end + def __cget_delegates(slot) + slot = slot.to_s + + if @option_methods.include?(slot) + if @option_methods[slot][:cget] + return self.__send__(@option_methods[slot][:cget]) + else + if @option_setting[slot] + return @option_setting[slot] + else + return '' + end + end + end + + tbl = @delegates[slot] + tbl = @delegates['DEFAULT'] unless tbl + + begin + if tbl + opt, wins = tbl[-1] + opt = slot if opt == 'DEFAULT' + if wins && wins[-1] + # return wins[-1].cget(opt) + return wins[-1].cget_strict(opt) + end + end + rescue + end + + return None + end + private :__cget_delegates + + def cget(slot) + if (ret = __cget_delegates(slot)) == None + super(slot) + else + ret + end + end + + def cget_strict(slot) + if (ret = __cget_delegates(slot)) == None + super(slot) + else + ret + end + end + +=begin def cget(slot) slot = slot.to_s @@ -212,6 +263,7 @@ module TkComposite super(slot) end +=end def configure(slot, value=None) if slot.kind_of? Hash diff --git a/ext/tk/lib/tk/event.rb b/ext/tk/lib/tk/event.rb index 0042fcaa63..d8aad6248b 100644 --- a/ext/tk/lib/tk/event.rb +++ b/ext/tk/lib/tk/event.rb @@ -352,6 +352,14 @@ module TkEvent nil ] + # [ <'%' subst-key str>, <proc type char>, <instance var (accessor) name>] + # the subst-key string will be converted to a bytecode (128+idx). + LONGKEY_TBL = [ + # for example, for %CTT and %CST subst-key on tkdnd-2.0 + # ['CTT', ?l, :drop_target_type], + # ['CST', ?l, :drop_source_type], + ] + # [ <proc type char>, <proc/method to convert tcl-str to ruby-obj>] PROC_TBL = [ [ ?n, TkComm.method(:num_or_str) ], @@ -371,6 +379,7 @@ module TkEvent nil ] +=begin # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) KEY_TBL.map!{|inf| if inf.kind_of?(Array) @@ -386,6 +395,7 @@ module TkEvent end inf } +=end # setup tables to be used by scan_args, _get_subst_key, _get_all_subst_keys # @@ -399,7 +409,8 @@ module TkEvent # ( which are Tcl strings ) to ruby objects based on the key string # that is generated by _get_subst_key() or _get_all_subst_keys(). # - _setup_subst_table(KEY_TBL, PROC_TBL); + _setup_subst_table(KEY_TBL, PROC_TBL) + # _setup_subst_table(KEY_TBL, LONGKEY_TBL, PROC_TBL) # if use longname-keys # # NOTE: The order of parameters which passed to callback procedure is @@ -447,6 +458,7 @@ module TkEvent extra_args_tbl = klass._get_extra_args_tbl if args.compact.size > 0 + args.map!{|arg| klass._sym2subst(arg)} args = args.join(' ') keys = klass._get_subst_key(args) diff --git a/ext/tk/lib/tk/font.rb b/ext/tk/lib/tk/font.rb index 4641d8a640..62d628c132 100644 --- a/ |