diff options
author | nagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2008-03-29 05:25:12 +0000 |
---|---|---|
committer | nagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2008-03-29 05:25:12 +0000 |
commit | e21c1b69d449c3c5248fe8fc97c37f3ae7b0d575 (patch) | |
tree | acfc67e481cd24c5e1ca2a344bd97e514fb26246 | |
parent | 5597c998bf489785d8c76ecd6251946a78460492 (diff) | |
download | ruby-e21c1b69d449c3c5248fe8fc97c37f3ae7b0d575.tar.gz ruby-e21c1b69d449c3c5248fe8fc97c37f3ae7b0d575.tar.xz ruby-e21c1b69d449c3c5248fe8fc97c37f3ae7b0d575.zip |
* ext/tk/*: full update Ruby/Tk to support Ruby(1.9|1.8) and Tc/Tk8.5.
* ext/tk/lib/tkextlib/tile.rb: [incompatible] remove TileWidgets'
instate/state/identify method to avoid the conflict with standard
widget options. Those methods are renamed to ttk_instate/ttk_state/
ttk_identify (tile_instate/tile_state/tile_identify are available
too). Although I don't recommend, if you realy need old methods,
please define "Tk::USE_OBSOLETE_TILE_STATE_METHOD = true" before
"require 'tkextlib/tile'".
* ext/tk/lib/tkextlib/tile.rb: "Tk::Tile::__Import_Tile_Widgets__!"
is obsolete. It outputs warning. To control default widget set,
use "Tk.default_widget_set = :Ttk".
* ext/tk/lib/tk.rb: __IGNORE_UNKNOWN_CONFIGURE_OPTION__ method and
__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) method are defind
as module methods of TkConfigMethod. It may help users to wrap old
Ruby/Tk scripts (use standard widgets) to force to use Ttk widgets.
Ttk widgets don't have some options of standard widgets which are
control the view of widgets. When set ignore-mode true, configure
method tries to ignoure such unknown options with no exception.
Of course, it may raise other troubles on the GUI design.
So, those are a little danger methods.
* ext/tk/lib/tk/itemconfig.rb: __IGNORE_UNKNOWN_CONFIGURE_OPTION__
method and __set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) method
are defind as module methods of TkItemConfigMethod as the same
purpose as TkConfigMethod's ones.
* ext/tk/sample/ttk_wrapper.rb: A new example. This is a tool for
wrapping old Ruby/Tk scripts (which use standard widgets) to use
Ttk (Tile) widgets as default.
* ext/tk/sample/tkextlib/tile/demo.rb: use ttk_instate/ttk_state
method instead of instate/state method.
* ext/tk/lib/tk/root, ext/tk/lib/tk/namespace.rb,
ext/tk/lib/tk/text.rb, ext/tk/lib/tkextlib/*: some 'instance_eval's
are replaced to "instance_exec(self)".
* ext/tk/lib/tk/event.rb: bug fix on KEY_TBL and PROC_TBL (?x is not
a character code on Ruby1.9).
* ext/tk/lib/tk/variable.rb: support new style of operation argument
on Tcl/Tk's 'trace' command for variables.
* ext/tk/sample/demos-jp/widget, ext/tk/sample/demos-en/widget: bug fix
* ext/tk/sammple/demos-jp/textpeer.rb,
ext/tk/sammple/demos-en/textpeer.rb: new widget demo.
* ext/tk/tcltklib.c: decrase SEGV troubles (probably)
* ext/tk/lib/tk.rb: remove Thread.critical access if Ruby1.9
* ext/tk/lib/tk/multi-tk.rb: support Ruby1.9 (probably)
* ext/tk/lib/tkextlib/tile.rb: add method to define Tcl/Tk command
to make Tcl/Tk theme sources (based on different version of Tile
extension) available.
(Tk::Tile::__define_LoadImages_proc_for_comaptibility__)
* ext/tk/lib/tk.rb, ext/tk/lib/tk/wm.rb: support dockable frames
(Tcl/Tk8.5 feature). 'wm' command can treat many kinds of widgets
as toplevel widgets.
* ext/tk/lib/tkextlib/tile/style.rb: ditto.
(Tk::Tile::Style.__define_wrapper_proc_for_compatibility__)
* ext/tk/lib/tk/font.rb: add actual_hash and metrics_hash to get
properties as a hash. metrics_hash method returns a boolean value
for 'fixed' option. But metrics method returns numeric value
(0 or 1) for 'fixed' option, because of backward compatibility.
* ext/tk/lib/tk/timer.rb: somtimes fail to set callback procedure.
* ext/tk/lib/tk.rb: add Tk.sleep and Tk.wakeup method. Tk.sleep
doesn't block the eventloop. It will be better to use the method
in event callbacks.
* ext/tk/sample/tksleep_sample.rb: sample script about Tk.sleep.
git-svn-id: http://svn.ruby-lang.org/repos/ruby/trunk@15848 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
121 files changed, 7855 insertions, 2194 deletions
@@ -1,3 +1,87 @@ +Sat Mar 29 14:18:41 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp> + + * ext/tk/*: full update Ruby/Tk to support Ruby(1.9|1.8) and Tc/Tk8.5. + + * ext/tk/lib/tkextlib/tile.rb: [incompatible] remove TileWidgets' + instate/state/identify method to avoid the conflict with standard + widget options. Those methods are renamed to ttk_instate/ttk_state/ + ttk_identify (tile_instate/tile_state/tile_identify are available + too). Although I don't recommend, if you realy need old methods, + please define "Tk::USE_OBSOLETE_TILE_STATE_METHOD = true" before + "require 'tkextlib/tile'". + + * ext/tk/lib/tkextlib/tile.rb: "Tk::Tile::__Import_Tile_Widgets__!" + is obsolete. It outputs warning. To control default widget set, + use "Tk.default_widget_set = :Ttk". + + * ext/tk/lib/tk.rb: __IGNORE_UNKNOWN_CONFIGURE_OPTION__ method and + __set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) method are defind + as module methods of TkConfigMethod. It may help users to wrap old + Ruby/Tk scripts (use standard widgets) to force to use Ttk widgets. + Ttk widgets don't have some options of standard widgets which are + control the view of widgets. When set ignore-mode true, configure + method tries to ignoure such unknown options with no exception. + Of course, it may raise other troubles on the GUI design. + So, those are a little danger methods. + + * ext/tk/lib/tk/itemconfig.rb: __IGNORE_UNKNOWN_CONFIGURE_OPTION__ + method and __set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) method + are defind as module methods of TkItemConfigMethod as the same + purpose as TkConfigMethod's ones. + + * ext/tk/sample/ttk_wrapper.rb: A new example. This is a tool for + wrapping old Ruby/Tk scripts (which use standard widgets) to use + Ttk (Tile) widgets as default. + + * ext/tk/sample/tkextlib/tile/demo.rb: use ttk_instate/ttk_state + method instead of instate/state method. + + * ext/tk/lib/tk/root, ext/tk/lib/tk/namespace.rb, + ext/tk/lib/tk/text.rb, ext/tk/lib/tkextlib/*: some 'instance_eval's + are replaced to "instance_exec(self)". + + * ext/tk/lib/tk/event.rb: bug fix on KEY_TBL and PROC_TBL (?x is not + a character code on Ruby1.9). + + * ext/tk/lib/tk/variable.rb: support new style of operation argument + on Tcl/Tk's 'trace' command for variables. + + * ext/tk/sample/demos-jp/widget, ext/tk/sample/demos-en/widget: bug fix + + * ext/tk/sammple/demos-jp/textpeer.rb, + ext/tk/sammple/demos-en/textpeer.rb: new widget demo. + + * ext/tk/tcltklib.c: decrase SEGV troubles (probably) + + * ext/tk/lib/tk.rb: remove Thread.critical access if Ruby1.9 + + * ext/tk/lib/tk/multi-tk.rb: support Ruby1.9 (probably) + + * ext/tk/lib/tkextlib/tile.rb: add method to define Tcl/Tk command + to make Tcl/Tk theme sources (based on different version of Tile + extension) available. + (Tk::Tile::__define_LoadImages_proc_for_comaptibility__) + + * ext/tk/lib/tk.rb, ext/tk/lib/tk/wm.rb: support dockable frames + (Tcl/Tk8.5 feature). 'wm' command can treat many kinds of widgets + as toplevel widgets. + + * ext/tk/lib/tkextlib/tile/style.rb: ditto. + (Tk::Tile::Style.__define_wrapper_proc_for_compatibility__) + + * ext/tk/lib/tk/font.rb: add actual_hash and metrics_hash to get + properties as a hash. metrics_hash method returns a boolean value + for 'fixed' option. But metrics method returns numeric value + (0 or 1) for 'fixed' option, because of backward compatibility. + + * ext/tk/lib/tk/timer.rb: somtimes fail to set callback procedure. + + * ext/tk/lib/tk.rb: add Tk.sleep and Tk.wakeup method. Tk.sleep + doesn't block the eventloop. It will be better to use the method + in event callbacks. + + * ext/tk/sample/tksleep_sample.rb: sample script about Tk.sleep. + Thu Mar 27 20:44:22 2008 Tadayoshi Funaba <tadf@dotrb.org> * complex.c (f_lcm): removed. diff --git a/ext/tk/MANUAL_tcltklib.eng b/ext/tk/MANUAL_tcltklib.eng index 9ef9adf26..6fa775b7d 100644 --- a/ext/tk/MANUAL_tcltklib.eng +++ b/ext/tk/MANUAL_tcltklib.eng @@ -448,6 +448,10 @@ class TclTkIp : slave interpreter, same to the TclTkLib module method with : the same name. + encoding_table + : For Ruby m17n. Return encoding relation table between Ruby's + : Encoding object and Tcl's encoding name. + class TkCallbackBreak < StandardError class TkCallbackContinue < StandardError : They are exception classes to break or continue the Tk callback @@ -458,5 +462,8 @@ class TkCallbackContinue < StandardError : If raise TkCallbackContinue, returns 'continue' code (Then the Tk : interpreter will break the operateion for the current bindtag and : starts the operation for the next buindtag for the current event). + : However, current tcltklib supports Ruby's 'break' and 'next' to + : get the same effect. That is, those classes are obsolete. Those + : exist for backward compatibility. (eof) diff --git a/ext/tk/MANUAL_tcltklib.eucj b/ext/tk/MANUAL_tcltklib.eucj index d291b7e80..7df42997b 100644 --- a/ext/tk/MANUAL_tcltklib.eucj +++ b/ext/tk/MANUAL_tcltklib.eucj @@ -559,6 +559,9 @@ require "tcltklib" ¤¹¤ë¤È, °Ê²¼¤Î¥â¥¸¥å¡¼¥ë, ¥¯¥é¥¹¤¬ÍøÍѲÄǽ¤Ç¤¹. : ¥¹¥ì¡¼¥Ö IP ¤Î¾ì¹ç¤Ë¤ÏÃͤÎÀßÄ꤬µö¤µ¤ì¤Ê¤¤ (̵»ë¤µ¤ì¤ë)¡¥ : ¤½¤ì°Ê³°¤ÎÅÀ¤Ç¤Ï°ú¿ô¤ò´Þ¤á¤Æ TclTkLib ¤ÎƱ̾¥á¥½¥Ã¥É¤ËƱ¤¸¡¥ + encoding_table + : Ruby m17n ÍÑ¤Ë Ruby ¤È Tk ¤È¤Î´Ö¤Î encoding Âбþɽ¤òÊÖ¤¹¡¥ + ¥¯¥é¥¹ TkCallbackBreak < StandardError ¥¯¥é¥¹ TkCallbackContinue < StandardError : ¤³¤ì¤é¤Ï¥¤¥Ù¥ó¥È¥³¡¼¥ë¥Ð¥Ã¥¯¤Ë¤ª¤¤¤Æ¡¤¥³¡¼¥ë¥Ð¥Ã¥¯½èÍý¤òŬÀÚ¤ËÃæ @@ -569,5 +572,8 @@ require "tcltklib" ¤¹¤ë¤È, °Ê²¼¤Î¥â¥¸¥å¡¼¥ë, ¥¯¥é¥¹¤¬ÍøÍѲÄǽ¤Ç¤¹. : ¥É¤òÊÖ¤¹É¬Íפ¬¤¢¤ë¡¥Ruby ¤Î¼ê³¤¤¬ÉáÄ̤ËÃͤòÊÖ¤¹¤Î¤Ç¤Ï¡¤¤½¤ì¤¬Éá : Ä̤ÎÌá¤êÃͤǤ¢¤ë¤Î¤«Èݤ«¤ò¶èÊ̤¬¤Ç¤¤Ê¤¤¤¿¤á¡¤Î㳰ȯÀ¸¤òÍøÍѤ·¤¿ : ¼ÂÁõ¤ò¹Ô¤Ã¤Æ¤¤¤ë¡¥ + : ¤¿¤À¤·¸½ºß¤Ç¤Ï¡¤¥³¡¼¥ë¥Ð¥Ã¥¯¼ê³¤¤ò Ruby ¤Î break, next ¤Ç½ªÎ»¤¹ + : ¤ë¤³¤È¤ÇƱÅù¤Î·ë²Ì¤òÆÀ¤ë¤³¤È¤¬¤Ç¤¤ë¤è¤¦¤Ë¤Ê¤Ã¤Æ¤¤¤ë¡¥¤½¤ì¤æ¤¨¡¤ + : ¤³¤ì¤é¤ÏɬÍפʤ¤¤â¤Î¤Ç¤Ï¤¢¤ë¤¬¡¤¸ß´¹À¤Î¤¿¤á¤Ë»Ä¤·¤Æ¤¢¤ë¡¥ (eof) diff --git a/ext/tk/README.tcltklib b/ext/tk/README.tcltklib index e939ba1f5..b94d77810 100644 --- a/ext/tk/README.tcltklib +++ b/ext/tk/README.tcltklib @@ -16,18 +16,18 @@ some or all of the following options. --with-tk-dir=<path> equal to "--with-tk-include=<path>/include --with-tk-lib=<path>/lib" - --with-tcl-include=<dir> the directry containts 'tcl.h' - --with-tk-include=<dir> the directry containts 'tk.h' + --with-tcl-include=<dir> the directry contains 'tcl.h' + --with-tk-include=<dir> the directry contains 'tk.h' - --with-tcl-lib=<dir> the directry containts 'libtcl<version>.so' - --with-tk-lib=<dir> the directry containts 'libtk<version>.so' + --with-tcl-lib=<dir> the directry contains 'libtcl<version>.so' + --with-tk-lib=<dir> the directry contains 'libtk<version>.so' --enable-mac-tcltk-framework (MacOS X) use Tcl/Tk framework (Obsolete. Please use '--enable-tcltk-framework'.) --enable-tcltk-framework use Tcl/Tk framework - --with-tcltk-framework=<dir> the directory containts Tcl/Tk framework; + --with-tcltk-framework=<dir> the directory contains Tcl/Tk framework; "<dir>/Tcl.framework" and "<dir>/Tk.framework". When this option is given, it is assumed that --enable-tcltk-framework option is given also. @@ -46,8 +46,8 @@ some or all of the following options. --with-X11-dir=<path> equal to "--with-X11-include=<path>/include --with-X11-lib=<path>/lib" - --with-X11-include=<dir> the directry contains X11 header files - --with-X11-lib=<dir> the directry contains X11 libraries + --with-X11-include=<dir> the directry contais X11 header files + --with-X11-lib=<dir> the directry contais X11 libraries If you forgot to give the options when do 'configure' on toplevel diff --git a/ext/tk/extconf.rb b/ext/tk/extconf.rb index 292b18a5c..cb7621fbd 100644 --- a/ext/tk/extconf.rb +++ b/ext/tk/extconf.rb @@ -2,7 +2,8 @@ require 'mkmf' -is_win32 = (/mswin32|mingw|cygwin|bccwin32/ =~ RUBY_PLATFORM) +#is_win32 = (/mswin32|mingw|cygwin|bccwin32/ =~ RUBY_PLATFORM) +is_win32 = (/mswin|mingw|cygwin|bccwin|wince/ =~ RUBY_PLATFORM) #is_macosx = (/darwin/ =~ RUBY_PLATFORM) def find_framework(tcl_hdr, tk_hdr) @@ -39,9 +40,13 @@ unless is_win32 have_library("m", "log") end -dir_config("tk") -dir_config("tcl") -dir_config("X11") +tk_idir, tk_ldir = dir_config("tk") +tcl_idir, tcl_ldir = dir_config("tcl") +x11_idir, x11_ldir = dir_config("X11") + +tk_ldir2 = with_config("tk-lib") +tcl_ldir2 = with_config("tcl-lib") +x11_ldir2 = with_config("X11-lib") tklib = with_config("tklib") tcllib = with_config("tcllib") @@ -49,8 +54,9 @@ stubs = enable_config("tcltk_stubs") || with_config("tcltk_stubs") use_X = with_config("X11", (! is_win32)) -def find_tcl(tcllib, stubs) - paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"] +def find_tcl(tcllib, stubs, *opt_paths) + default_paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"] + paths = opt_paths.compact.concat(default_paths) if stubs func = "Tcl_InitStubs" lib = "tclstub" @@ -60,24 +66,23 @@ def find_tcl(tcllib, stubs) end if tcllib find_library(tcllib, func, *paths) - elsif find_library(lib, func, *paths) - true 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("tcl#{ver}", func, *paths) or - find_library("tcl#{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) end end -def find_tk(tklib, stubs) - paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"] +def find_tk(tklib, stubs, *opt_paths) + default_paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"] + paths = opt_paths.compact.concat(default_paths) if stubs func = "Tk_InitStubs" lib = "tkstub" @@ -87,22 +92,27 @@ def find_tk(tklib, stubs) end if tklib find_library(tklib, func, *paths) - elsif find_library(lib, func, *paths) - true 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("tk#{ver}", func, *paths) or - find_library("tk#{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) end 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) +end + def pthread_check() tcl_major_ver = nil tcl_minor_ver = nil @@ -281,13 +291,11 @@ EOF end end -if tcltk_framework || - (have_header("tcl.h") && have_header("tk.h") && - ( !use_X || find_library("X11", "XOpenDisplay", - "/usr/X11/lib", "/usr/lib/X11", - "/usr/X11R6/lib", "/usr/openwin/lib")) && - find_tcl(tcllib, stubs) && - find_tk(tklib, stubs)) +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) ) ) $CPPFLAGS += ' -DUSE_TCL_STUBS -DUSE_TK_STUBS' if stubs $CPPFLAGS += ' -D_WIN32' if /cygwin/ =~ RUBY_PLATFORM diff --git a/ext/tk/lib/multi-tk.rb b/ext/tk/lib/multi-tk.rb index ed936bf1a..fd9a86388 100644 --- a/ext/tk/lib/multi-tk.rb +++ b/ext/tk/lib/multi-tk.rb @@ -114,7 +114,14 @@ MultiTkIp_OK.freeze class MultiTkIp BASE_DIR = File.dirname(__FILE__) - @@SLAVE_IP_ID = ['slave'.freeze, '0'.taint].freeze + WITH_RUBY_VM = Object.const_defined?(:VM) && ::VM.class == Class + WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class + + (@@SLAVE_IP_ID = ['slave'.freeze, '0'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } @@IP_TABLE = {}.taint unless defined?(@@IP_TABLE) @@ -126,7 +133,11 @@ class MultiTkIp unless defined?(@@TK_CMD_TBL) @@TK_CMD_TBL = Object.new.taint - @@TK_CMD_TBL.instance_variable_set('@tbl', {}.taint) + # @@TK_CMD_TBL.instance_variable_set('@tbl', {}.taint) + @@TK_CMD_TBL.instance_variable_set('@tbl', Hash.new{|hash,key| + fail IndexError, + "unknown command ID '#{key}'" + }.taint) class << @@TK_CMD_TBL allow = [ @@ -573,7 +584,11 @@ class MultiTkIp # raise exception begin bt = _toUTF8(e.backtrace.join("\n")) - bt.instance_variable_set(:@encoding, 'utf-8') + if MultiTkIp::WITH_ENCODING + bt.force_encoding('utf-8') + else + bt.instance_variable_set(:@encoding, 'utf-8') + end rescue Exception bt = e.backtrace.join("\n") end @@ -695,7 +710,10 @@ class MultiTkIp ###################################### - WITH_RUBY_VM = Object.const_defined?(:VM) && ::VM.class == Class + unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD + ### Ruby 1.9 !!!!!!!!!!!!!!!!!!!!!!!!!! + RUN_EVENTLOOP_ON_MAIN_THREAD = false + end if self.const_defined? :DEFAULT_MASTER_NAME name = DEFAULT_MASTER_NAME.to_s @@ -725,13 +743,24 @@ class MultiTkIp fail ArgumentError, "expecting a Hash object for the 2nd argument" end - unless WITH_RUBY_VM + if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!! @interp = TclTkIp.new(name, _keys2opts(keys)) else ### Ruby 1.9 !!!!!!!!!!! @interp_thread = Thread.new{ - Thread.current[:interp] = interp = TclTkIp.new(name, _keys2opts(keys)) + current = Thread.current + current[:interp] = interp = TclTkIp.new(name, _keys2opts(keys)) #sleep - interp.mainloop(true) + current[:mutex] = mutex = Mutex.new + current[:root_check] = cond_var = ConditionVariable.new + + begin + current[:status] = interp.mainloop(true) + rescue Exception=>e + current[:status] = e + ensure + mutex.synchronize{ cond_var.broadcast } + end + current[:status] = interp.mainloop(false) } until @interp_thread[:interp] Thread.pass @@ -976,9 +1005,11 @@ class MultiTkIp private :_parse_slaveopts def _create_slave_ip_name - name = @@SLAVE_IP_ID.join('') - @@SLAVE_IP_ID[1].succ! - name.freeze + @@SLAVE_IP_ID.mutex.synchronize{ + name = @@SLAVE_IP_ID.join('') + @@SLAVE_IP_ID[1].succ! + name.freeze + } end private :_create_slave_ip_name @@ -1309,11 +1340,11 @@ class MultiTkIp @@DEFAULT_MASTER.assign_receiver_and_watchdog(self) @@IP_TABLE[@threadgroup] = self - _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS) @@TK_TABLE_LIST.size.times{ (tbl = {}).tainted? || tbl.taint @tk_table_list << tbl } + _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS) class << self undef :instance_eval @@ -1391,8 +1422,13 @@ class << MultiTkIp alias __new new private :__new - def new_master(safe=nil, keys={}) + if MultiTkIp::WITH_RUBY_VM + #### TODO !!!!!! + fail RuntimeError, + 'sorry, still not support multiple master-interpreters on Ruby VM' + end + if safe.kind_of?(Hash) keys = safe elsif safe.kind_of?(Integer) @@ -1609,8 +1645,13 @@ class MultiTkIp return if slave? names.each{|name| name = name.to_s + + return if @interp.deleted? @interp._invoke('rename', name, '') + + return if @interp.deleted? @interp._invoke('interp', 'slaves').split.each{|slave| + return if @interp.deleted? @interp._invoke('interp', 'alias', slave, name, '') rescue nil } } @@ -1660,11 +1701,16 @@ class MultiTkIp id = @@TK_TABLE_LIST.size obj = Object.new @@TK_TABLE_LIST << obj - obj.instance_eval <<-EOD + obj.instance_variable_set(:@id, id) + obj.instance_variable_set(:@mutex, Mutex.new) + obj.instance_eval{ + def self.mutex + @mutex + end def self.method_missing(m, *args) - MultiTkIp.tk_object_table(#{id}).__send__(m, *args) + MultiTkIp.tk_object_table(@id).__send__(m, *args) end - EOD + } obj.freeze @@IP_TABLE.each{|tg, ip| ip._add_new_tables } return obj @@ -2797,9 +2843,10 @@ class MultiTkIp i = -1 brace = 1 str.each_byte {|c| + c = c.chr i += 1 - brace += 1 if c == ?{ - brace -= 1 if c == ?} + brace += 1 if c == '{' + brace -= 1 if c == '}' break if brace == 0 } if i == 0 @@ -3238,15 +3285,44 @@ end # encoding convert +class << MultiTkIp + def encoding_table + __getip.encoding_table + end +end class MultiTkIp - def encoding + def encoding_table + @interp.encoding_table + end + + def force_default_encoding=(mode) raise SecurityError, "no permission to manipulate" unless self.manipulable? - @interp.encoding + @interp.force_default_encoding = mode end + def force_default_encoding? + raise SecurityError, "no permission to manipulate" unless self.manipulable? + @interp.force_default_encoding? + end + + def default_encoding=(enc) + raise SecurityError, "no permission to manipulate" unless self.manipulable? + @interp.default_encoding = enc + end + def encoding=(enc) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.encoding = enc end + def encoding_name + raise SecurityError, "no permission to manipulate" unless self.manipulable? + @interp.encoding_name + end + def encoding_obj + raise SecurityError, "no permission to manipulate" unless self.manipulable? + @interp.encoding_obj + end + alias encoding encoding_name + alias default_encoding encoding_name def encoding_convertfrom(str, enc=None) raise SecurityError, "no permission to manipulate" unless self.manipulable? @@ -3264,12 +3340,28 @@ end # remove methods for security class MultiTkIp + INTERP_THREAD = @@DEFAULT_MASTER.instance_variable_get('@interp_thread') + INTERP_MUTEX = INTERP_THREAD[:mutex] + INTERP_ROOT_CHECK = INTERP_THREAD[:root_check] + # undef_method :instance_eval undef_method :instance_variable_get undef_method :instance_variable_set end - +module TkCore + if MultiTkIp::WITH_RUBY_VM && + ! MultiTkIp::RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!! + INTERP_THREAD = MultiTkIp::INTERP_THREAD + INTERP_MUTEX = MultiTkIp::INTERP_MUTEX + INTERP_ROOT_CHECK = MultiTkIp::INTERP_ROOT_CHECK + end +end +class MultiTkIp + remove_const(:INTERP_THREAD) + remove_const(:INTERP_MUTEX) + remove_const(:INTERP_ROOT_CHECK) +end # end of MultiTkIp definition # defend against modification diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb index d80271a32..0d00ecf20 100644 --- a/ext/tk/lib/tk.rb +++ b/ext/tk/lib/tk.rb @@ -9,6 +9,9 @@ require 'tkutil' # autoload require 'tk/autoload' +# for Mutex +require 'thread' + class TclTkIp # backup original (without encoding) _eval and _invoke alias _eval_without_enc _eval @@ -36,7 +39,12 @@ module TkComm #Tk_CMDTBL = {} #Tk_WINDOWS = {} - Tk_IDs = ["00000".taint, "00000".taint].freeze # [0]-cmdid, [1]-winid + Tk_IDs = ["00000".taint, "00000".taint] # [0]-cmdid, [1]-winid + Tk_IDs.instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } # for backward compatibility Tk_CMDTBL = Object.new @@ -217,7 +225,9 @@ module TkComm TkCore::INTERP.tk_windows[val]? TkCore::INTERP.tk_windows[val] : _genobj_for_tkwidget(val) when /\Ai(_\d+_)?\d+\z/ - TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val + TkImage::Tk_IMGTBL.mutex.synchronize{ + TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val + } when /\A-?\d+\.?\d*(e[-+]?\d+)?\z/ val.to_f when /\\ / @@ -334,6 +344,8 @@ if USE_TCLs_LIST_FUNCTIONS if dst_enc != true && dst_enc != false if (s_enc = s.instance_variable_get(:@encoding)) s_enc = s_enc.to_s + elsif TkCore::WITH_ENCODING + s_enc = s.encoding.name else s_enc = sys_enc end @@ -346,11 +358,20 @@ if USE_TCLs_LIST_FUNCTIONS if sys_enc && dst_enc dst.map!{|s| _toUTF8(s)} ret = TkCore::INTERP._merge_tklist(*dst) - if dst_enc.kind_of?(String) - ret = _fromUTF8(ret, dst_enc) - ret.instance_variable_set(:@encoding, dst_enc) - else - ret.instance_variable_set(:@encoding, 'utf-8') + if TkCore::WITH_ENCODING + if dst_enc.kind_of?(String) + ret = _fromUTF8(ret, dst_enc) + ret.force_encoding(dst_enc) + else + ret.force_encoding('utf-8') + end + else # without encoding + if dst_enc.kind_of?(String) + ret = _fromUTF8(ret, dst_enc) + ret.instance_variable_set(:@encoding, dst_enc) + else + ret.instance_variable_set(:@encoding, 'utf-8') + end end ret else @@ -410,46 +431,6 @@ else tk_split_sublist(token, depth - 1) } end -=begin - def tk_split_list(str) - return [] if str == "" - idx = str.index('{') - while idx and idx > 0 and str[idx-1] == ?\\ - idx = str.index('{', idx+1) - end - unless idx - list = tk_tcl2ruby(str) - unless Array === list - list = [list] - end - return list - end - - list = tk_tcl2ruby(str[0,idx]) - list = [] if list == "" - str = str[idx+1..-1] - i = -1 - escape = false - brace = 1 - str.each_byte {|c| - i += 1 - brace += 1 if c == ?{ && !escape - brace -= 1 if c == ?} && !escape - escape = (c == ?\\) - break if brace == 0 - } - if str.size == i + 1 - return tk_split_list(str[0, i]) - end - 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 -=end def tk_split_simplelist(str, src_enc=true, dst_enc=true) return [] if str == "" @@ -600,7 +581,9 @@ end end def image_obj(val) if val =~ /^i(_\d+_)?\d+$/ - TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val + TkImage::Tk_IMGTBL.mutex.synchronize{ + TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val + } else val end @@ -782,10 +765,12 @@ end id = "c" + TkCore::INTERP._ip_id_ + TkComm::Tk_IDs[0] end def _next_cmd_id - id = _curr_cmd_id - #Tk_IDs[0] += 1 - TkComm::Tk_IDs[0].succ! - id + TkComm::Tk_IDs.mutex.synchronize{ + id = _curr_cmd_id + #Tk_IDs[0] += 1 + TkComm::Tk_IDs[0].succ! + id + } end private :_curr_cmd_id, :_next_cmd_id module_function :_curr_cmd_id, :_next_cmd_id @@ -855,8 +840,10 @@ end return TkCore::INTERP.tk_windows[@path] = self end else - name = "w" + TkCore::INTERP._ip_id_ + Tk_IDs[1] - Tk_IDs[1].succ! + Tk_IDs.mutex.synchronize{ + name = "w" + TkCore::INTERP._ip_id_ + Tk_IDs[1] + Tk_IDs[1].succ! + } end if !ppath or ppath == '.' @path = '.' + name @@ -935,7 +922,12 @@ module TkComm def _bindinfo(what, context=nil) if context - tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]).each_line.collect {|cmdline| + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + enum_obj = tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]).each_line + else + enum_obj = tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]) + end + enum_obj.collect {|cmdline| =begin if cmdline =~ /^rb_out\S* (c(?:_\d+_)?\d+)\s+(.*)$/ #[Tk_CMDTBL[$1], $2] @@ -1106,10 +1098,9 @@ module TkCore opts = '' end - if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### Ruby 1.9 !!!!!!!!!!! + if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!! INTERP = TclTkIp.new(name, opts) else - require 'thread' INTERP_MUTEX = Mutex.new INTERP_ROOT_CHECK = ConditionVariable.new INTERP_THREAD = Thread.new{ @@ -1146,7 +1137,10 @@ module TkCore end INTERP.instance_eval{ - @tk_cmd_tbl = {}.taint + # @tk_cmd_tbl = {}.taint + @tk_cmd_tbl = Hash.new{|hash, key| + fail IndexError, "unknown command ID '#{key}'" + }.taint def @tk_cmd_tbl.[]=(idx,val) if self.has_key?(idx) && Thread.current.group != ThreadGroup::Default fail SecurityError,"cannot change the entried command" @@ -1197,6 +1191,10 @@ module TkCore class Tk_OBJECT_TABLE def initialize(id) @id = id + @mutex = Mutex.new + end + def mutex + @mutex end def method_missing(m, *args, &b) TkCore::INTERP.tk_object_table(@id).__send__(m, *args, &b) @@ -1382,7 +1380,11 @@ module TkCore "\n---< backtrace of Ruby side >-----\n" + _toUTF8(e.backtrace.join("\n")) + "\n---< backtrace of Tk side >-------" - msg.instance_variable_set(:@encoding, 'utf-8') + if TkCore::WITH_ENCODING + msg.force_encoding('utf-8') + else + msg.instance_variable_set(:@encoding, 'utf-8') + end rescue Exception msg = e.class.inspect + ': ' + e.message + "\n" + "\n---< backtrace of Ruby side >-----\n" + @@ -1438,6 +1440,11 @@ module TkCore end 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 + end +=begin + def after(ms, cmd=Proc.new) crit_bup = Thread.critical Thread.critical = true @@ -1460,8 +1467,14 @@ module TkCore # tk_call("after",ms,cmdid) # end end +=end def after_idle(cmd=Proc.new) + cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret}) + tk_call_without_enc('after','idle',cmdid) + end +=begin + def after_idle(cmd=Proc.new) crit_bup = Thread.critical Thread.critical = true @@ -1472,6 +1485,7 @@ module TkCore tk_call_without_enc('after','idle',cmdid) end +=end def after_cancel(afterId) tk_call_without_enc('after','cancel',afterId) @@ -1595,9 +1609,8 @@ module TkCore def mainloop(check_root = true) if !TkCore::WITH_RUBY_VM || TkCore::RUN_EVENTLOOP_ON_MAIN_THREAD - ### Ruby 1.9 !!!!!!!!!!! TclTkLib.mainloop(check_root) - else + else ### Ruby 1.9 !!!!! begin TclTkLib.set_eventloop_window_mode(true) if check_root @@ -2096,6 +2109,27 @@ module Tk tk_call_without_enc('destroy', '.') end + ################################################ + + def Tk.sleep(ms = nil, id = nil) + if id + var = (id.kind_of?(TkVariable))? id: TkVarAccess.new(id.to_s) + else + var = TkVariable.new + end + + var.value = tk_call_without_enc('after', ms, proc{ var.value = 0 }) if ms + var.thread_wait + ms + end + + def Tk.wakeup(id) + ((id.kind_of?(TkVariable))? id: TkVarAccess.new(id.to_s)).value = 0 + nil + end + + ################################################ + def Tk.pack(*args) TkPack.configure(*args) end @@ -2271,16 +2305,432 @@ end # convert kanji string to/from utf-8 ########################################### if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) + module Tk + module Encoding + extend Encoding + + TkCommandNames = ['encoding'.freeze].freeze + + ############################################# + + if TkCore::WITH_ENCODING ### Ruby 1.9 + RubyEncoding = ::Encoding + + # for saving GC cost + #ENCNAMES_CMD = ['encoding'.freeze, 'names'.freeze] + BINARY_NAME = 'binary'.freeze + UTF8_NAME = 'utf-8'.freeze + DEFAULT_EXTERNAL_NAME = RubyEncoding.default_external.name.freeze + + BINARY = RubyEncoding.find(BINARY_NAME) + UNKNOWN = RubyEncoding.find('ASCII-8BIT') + + ### start of creating ENCODING_TABLE + ENCODING_TABLE = TkCore::INTERP.encoding_table +=begin + ENCODING_TABLE = { + 'binary' => BINARY, + # 'UNKNOWN-8BIT' => UNKNOWN, + } + + list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0], + ENCNAMES_CMD[1]) + TkCore::INTERP._split_tklist(list).each{|name| + begin + enc = RubyEncoding.find(name) + rescue ArgumentError + case name + when 'identity' + enc = BINARY + when 'shiftjis' + enc = RubyEncoding.find('Shift_JIS') + when 'unicode' + enc = RubyEncoding.find('UTF-8') + #if Tk.tk_call('set', 'tcl_platform(byteOrder)') =='littleEndian' + # enc = RubyEncoding.find('UTF-16LE') + #else + # enc = RubyEncoding.find('UTF-16BE') + #end + when 'symbol' + # single byte data + enc = RubyEncoding.find('ASCII-8BIT') ### ??? + else + # unsupported on Ruby, but supported on Tk + enc = TkCore::INTERP.create_dummy_encoding_for_tk(name) + end + end + ENCODING_TABLE[name.freeze] = enc + } +=end +=begin + def ENCODING_TABLE.get_name(enc) + orig_enc = enc + + # unles enc, use system default + # 1st: Ruby/Tk default encoding + # 2nd: Tcl/Tk default encoding + # 3rd: Ruby's default_external + enc ||= TkCore::INTERP.encoding + enc ||= TclTkLib.encoding_system + enc ||= DEFAULT_EXTERNAL_NAME + + if enc.kind_of?(RubyEncoding) + # Ruby's Encoding object + if (name = self.key(enc)) + return name + end + + # Is it new ? + list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0], + ENCNAMES_CMD[1]) + TkComm.simplelist(list).each{|name| + if ((enc == RubyEncoding.find(name)) rescue false) + # new relation!! update table + self[name.freeze] = enc + return name + end + } + else + # String or Symbol ? + if self[name = enc.to_s] + return name + end + + # Is it new ? + if (enc_obj = (RubyEncoding.find(name) rescue false)) + list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0], + ENCNAMES_CMD[1]) + if TkComm.simplelist(list).index(name) + # Tk's encoding name ? + self[name.freeze] = enc_obj # new relation!! update table + return name + else + # Ruby's encoding name ? + if (name = self.key(enc_obj)) + return name + end + end + end + end + + fail ArgumentError, "unsupported Tk encoding '#{orig_enc}'" + end + + def ENCODING_TABLE.get_obj(enc) + # returns the encoding object. + # If 'enc' is the encoding name on Tk only, it returns nil. + ((obj = self[self.get_name(enc)]).kind_of?(RubyEncoding))? obj: nil + end +=end + ### end of creating ENCODING_TABLE + + end + + ############################################# + + if TkCore::WITH_ENCODING + ################################ + ### Ruby 1.9 + ################################ + def force_default_encoding(mode) + TkCore::INTERP.force_default_encoding = mode + end + + def force_default_encoding? + TkCore::INTERP.force_default_encoding? + end + + def default_encoding=(enc) + TkCore::INTERP.default_encoding = Tk::Encoding::ENCODING_TABLE.get_name(enc) + end + + def encoding=(enc) + TkCore::INTERP.encoding = Tk::Encoding::ENCODING_TABLE.get_name(enc) + end + + def encoding_name + Tk::Encoding::ENCODING_TABLE.get_name(TkCore::INTERP.encoding) + end + def encoding_obj + Tk::Encoding::ENCODING_TABLE.get_obj(TkCore::INTERP.encoding) + end + alias encoding encoding_name + 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])) + end + def encoding_names + self.tk_encoding_names.find_all{|name| + Tk::Encoding::ENCODING_TABLE.get_name(name) rescue false + } + end + def encoding_objs + self.tk_encoding_names.map!{|name| + Tk::Encoding::ENCODING_TABLE.get_obj(name) rescue nil + }.compact + end + + def encoding_system=(enc) + TclTkLib.encoding_system = Tk::Encoding::ENCODING_TABLE.get_name(enc) + end + + def encoding_system_name + Tk::Encoding::ENCODING_TABLE.get_name(TclTkLib.encoding_system) + end + def encoding_system_obj + Tk::Encoding::ENCODING_TABLE.get_obj(TclTkLib.encoding_system) + end + alias encoding_system encoding_system_name + + ################################ + else + ################################ + ### Ruby 1.8- + ################################ + def force_default_encoding=(mode) + true + end + + def force_default_encoding? + true + end + + def default_encoding=(enc) + TkCore::INTERP.default_encoding = enc + end + + def encoding=(enc) + TkCore::INTERP.encoding = enc + end + + def encoding_obj + TkCore::INTERP.encoding + end + def encoding_name + TkCore::INTERP.encoding + end + alias encoding encoding_name + alias default_encoding encoding_name + + def tk_encoding_names + TkComm.simplelist(Tk.tk_call('encoding', 'names')) + end + def encoding_objs + self.tk_encoding_names + end + def encoding_names + self.tk_encoding_names + end + + def encoding_system=(enc) + TclTkLib.encoding_system = enc + end + + def encoding_system_name + TclTkLib.encoding_system + end + def encoding_system_obj + TclTkLib.encoding_system + end + alias encoding_system encoding_system_name + + ################################ + end + + def encoding_convertfrom(str, enc=nil) + enc = encoding_system_name unless enc + str = str.dup + if TkCore::WITH_ENCODING + if str.kind_of?(Tk::EncodedString) + str.__instance_variable_set('@encoding', nil) + else + str.instance_variable_set('@encoding', nil) + end + str.force_encoding('binary') + else + str.instance_variable_set('@encoding', 'binary') + end + ret = TkCore::INTERP._invoke_without_enc('encoding', 'convertfrom', + enc, str) + if TkCore::WITH_ENCODING + ret.force_encoding('utf-8') + else + Tk::UTF8_String.new(ret) + end + ret + end + alias encoding_convert_from encoding_convertfrom + + def encoding_convertto(str, enc=nil) + # str must be a UTF-8 string + enc = encoding_system_name unless enc + ret = TkCore::INTERP._invoke_without_enc('encoding', 'convertto', + enc, str) + #ret.instance_variable_set('@encoding', 'binary') + if TkCore::WITH_ENCODING + #ret.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj('binary')) + ret.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj(enc)) + end + ret + end + alias encoding_convert_to encoding_convertto + + def encoding_dirs + # Tcl8.5 feature + TkComm.simplelist(Tk.tk_call_without_enc('encoding', 'dirs')) + end + + def encoding_dirs=(dir_list) # an array or a Tcl's list string + # Tcl8.5 feature + Tk.tk_call_without_enc('encoding', 'dirs', dir_list) + end + end + + extend Encoding + end + class TclTkIp + def force_default_encoding=(mode) + @force_default_encoding = (mode)? true: false + end + + def force_default_encoding? + @force_default_encoding ||= false + end + + def default_encoding=(name) + name = name.name if name.kind_of?(::Encoding) if Tk::WITH_ENCODING + @encoding = name + end + # from tkencoding.rb by ttate@jaist.ac.jp - attr_accessor :encoding + #attr_accessor :encoding + def encoding=(name) + self.force_default_encoding = true # for comaptibility + self.default_encoding = name + end - alias __eval _eval - alias __invoke _invoke + def encoding_name + (@encoding)? @encoding.dup: nil + end + alias encoding encoding_name + alias default_encoding encoding_name + + def encoding_obj + if Tk::WITH_ENCODING + Tk::Encoding.tcl2rb_encoding(@encoding) + else + (@encoding)? @encoding.dup: nil + end + end alias __toUTF8 _toUTF8 alias __fromUTF8 _fromUTF8 + if Object.const_defined?(:Encoding) && ::Encoding.class == Class + # with Encoding (Ruby 1.9+) + # + # use functions on Tcl as default. + # but when unsupported encoding on Tcl, use methods on Ruby. + # + def _toUTF8(str, enc = nil) + if enc + # use given encoding + begin + enc_name = Tk::Encoding::ENCODING_TABLE.get_name(enc) + rescue + # unknown encoding for Tk -> try to convert encoding on Ruby + str = str.dup.force_encoding(enc) + str.encode!(Tk::Encoding::UTF8_NAME) # modify self !! + return str # if no error, probably succeed converting + end + end + + enc_name ||= str.instance_variable_get(:@encoding) + + enc_name ||= + Tk::Encoding::ENCODING_TABLE.get_name(str.encoding) rescue nil + + unless enc_name + # str.encoding isn't supported by Tk -> try to convert on Ruby + begin + return str.encode(Tk::Encoding::UTF8_NAME) # new string + rescue + # error -> ignore, try to use default encoding of Ruby/Tk + end + end + + #enc_name ||= + # Tk::Encoding::ENCODING_TABLE.get_name(Tk.encoding) rescue nil + enc_name ||= Tk::Encoding::ENCODING_TABLE.get_name(nil) + + # is 'binary' encoding? + if enc_name == Tk::Encoding::BINARY_NAME + return str.dup.force_encoding(Tk::Encoding::BINARY_NAME) + end + + # force default encoding? + if ! str.kind_of?(Tk::EncodedString) && self.force_default_encoding? + enc_name = Tk::Encoding::ENCODING_TABLE.get_name(Tk.default_encoding) + end + + encstr = __toUTF8(str, enc_name) + encstr.force_encoding(Tk::Encoding::UTF8_NAME) + encstr + end + def _fromUTF8(str, enc = nil) + # str must be UTF-8 or binary. + enc_name = str.instance_variable_get(:@encoding) + enc_name ||= + Tk::Encoding::ENCODING_TABLE.get_name(str.encoding) rescue nil + + # is 'binary' encoding? + if enc_name == Tk::Encoding::BINARY_NAME + return str.dup.force_encoding(Tk::Encoding::BINARY_NAME) + end + + # get target encoding name (if enc == nil, use default encoding) + begin + enc_name = Tk::Encoding::ENCODING_TABLE.get_name(enc) + rescue + # then, enc != nil + # unknown encoding for Tk -> try to convert encoding on Ruby + str = str.dup.force_encoding(Tk::Encoding::UTF8_NAME) + str.encode!(enc) # modify self !! + return str # if no error, probably succeed converting + end + + encstr = __fromUTF8(str, enc_name) + encstr.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj(enc_name)) + encstr + end + ### + else + # without Encoding (Ruby 1.8) + def _toUTF8(str, encoding = nil) + __toUTF8(str, encoding) + end + def _fromUTF8(str, encoding = nil) + __fromUTF8(str, encoding) + end + ### + end + + alias __eval _eval + alias __invoke _invoke + + def _eval(cmd) + _fromUTF8(__eval(_toUTF8(cmd))) + end + + def _invoke(*cmds) + _fromUTF8(__invoke(*(cmds.collect{|cmd| _toUTF8(cmd)}))) + end + + alias _eval_with_enc _eval + alias _invoke_with_enc _invoke + =begin #### --> definition is moved to TclTkIp module @@ -2330,17 +2780,6 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) end =end - def _eval(cmd) - _fromUTF8(__eval(_toUTF8(cmd))) - end - - def _invoke(*cmds) - _fromUTF8(__invoke(*(cmds.collect{|cmd| _toUTF8(cmd)}))) - end - - alias _eval_with_enc _eval - alias _invoke_with_enc _invoke - =begin def _eval(cmd) if defined?(@encoding) && @encoding != 'utf-8' @@ -2397,81 +2836,43 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) module TclTkLib class << self - alias _encoding encoding - alias _encoding= encoding= - def encoding=(name) - TkCore::INTERP.encoding = name - end - def encoding - TkCore::INTERP.encoding + def force_default_encoding=(mode) + TkCore::INTERP.force_default_encoding = mode end - end - end - module Tk - module Encoding - extend Encoding + def force_default_encoding? + TkCore::INTERP.force_default_encoding? + end - TkCommandNames = ['encoding'.freeze].freeze + def default_encoding=(name) + TkCore::INTERP.default_encoding = name + end + alias _encoding encoding + alias _encoding= encoding= def encoding=(name) + name = name.name if name.kind_of?(::Encoding) if Tk::WITH_ENCODING TkCore::INTERP.encoding = name end - def encoding + def encoding_name TkCore::INTERP.encoding end + alias encoding encoding_name + alias default_encoding encoding_name - def encoding_names - TkComm.simplelist(Tk.tk_call('encoding', 'names')) - end - - def encoding_system - Tk.tk_call('encoding', 'system') - end - - def encoding_system=(enc) - Tk.tk_call('encoding', 'system', enc) - end - - def encoding_convertfrom(str, enc=nil) - # str is an usual enc string or a Tcl's internal string expression - # in enc (which is returned from 'encoding_convertto' method). - # the return value is a UTF-8 string. - enc = encoding_system unless enc - ret = TkCore::INTERP.__invoke('encoding', 'convertfrom', enc, str) - ret.instance_variable_set('@encoding', 'utf-8') - ret - end - alias encoding_convert_from encoding_convertfrom - - def encoding_convertto(str, enc=nil) - # str must be a UTF-8 string. - # The return value is a Tcl's internal string expression in enc. - # To get an usual enc string, use Tk.fromUTF8(ret_val, enc). - enc = encoding_system unless enc - ret = TkCore::INTERP.__invoke('encoding', 'convertto', enc, str) - ret.instance_variable_set('@encoding', 'binary') - ret - end - alias encoding_convert_to encoding_convertto - - def encoding_dirs - # Tcl8.5 feature - TkComm.simplelist(Tk.tk_call_without_enc('encoding', 'dirs')) - end - - def encoding_dirs=(dir_list) # an array or a Tcl's list string - # Tcl8.5 feature - Tk.tk_call_without_enc('encoding', 'dirs', dir_list) + def encoding_obj + if Tk::WITH_ENCODING + Tk::Encoding.tcl2rb_encoding(TkCore::INTERP.encoding) + else + TkCore::INTERP.encoding + end end end - - extend Encoding end # estimate encoding - unless TkCore::WITH_ENCODING ### Ruby 1.9 !!!!!!!!!!!! + unless TkCore::WITH_ENCODING case $KCODE when /^e/i # EUC Tk.encoding = 'euc-jp' @@ -2502,89 +2903,147 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) Tk.encoding_system = 'utf-8' end end - else ######################### - $TK_ENCODING ||= Encoding.default_external.name - case $TK_ENCODING - when 'US_ASCII' - Tk.encoding = 'ascii' - Tk.encoding_system = 'ascii' - when 'BIG5' - Tk.encoding = 'big5' - Tk.encoding_system = 'big5' - when 'CP1251' - Tk.encoding = 'cp1251' - Tk.encoding_system = 'cp1251' - when 'EUC-JP' - Tk.encoding = 'euc-jp' - Tk.encoding_system = 'euc-jp' - when 'EUC-KR' - Tk.encoding = 'euc-kr' - Tk.encoding_system = 'euc-kr' - when 'EUC-TW', 'EUC-CN' - Tk.encoding = 'euc-cn' - Tk.encoding_system = 'euc-cn' - #when 'GB18030' - # Tk.encoding = 'gb12345' # ???????????? - # Tk.encoding_system = 'gb12345' # ???????????? - when 'ISO-2022-JP' - Tk.encoding = 'iso2022-jp' - Tk.encoding_system = 'iso2022-jp' - when /ISO-8859-(.*)/ - Tk.encoding = 'iso8859-' << $1 - Tk.encoding_system = 'iso8859-' << $1 - #when 'KOI8', 'KOI8-U' - # Tk.encoding = 'koi8-u' # ???????????? - # Tk.encoding_system = 'koi8-u' # ???????????? - when 'KOI8-R' - Tk.encoding = 'koi8-r' - Tk.encoding_system = 'koi8-r' - when 'Shift_JIS' - begin - if Tk.encoding_system == 'cp932' - Tk.encoding = 'cp932' + + else ### Ruby 1.9 !!!!!!!!!!!! + loc_enc_obj = ::Encoding.find(::Encoding.locale_charmap) + ext_enc_obj = ::Encoding.default_external + tksys_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(Tk.encoding_system) + # p [Tk.encoding, Tk.encoding_system, loc_enc_obj, ext_enc_obj] + +=begin + if ext_enc_obj == Tk::Encoding::UNKNOWN + if defind? DEFAULT_TK_ENCODING + if DEFAULT_TK_ENCODING.kind_of?(::Encoding) + tk_enc_name = DEFAULT_TK_ENCODING.name + tksys_enc_name = DEFAULT_TK_ENCODING.name else - Tk.encoding = 'shiftjis' - Tk.encoding_system = 'shiftjis' + tk_enc_name = DEFAULT_TK_ENCODING + tksys_enc_name = DEFAULT_TK_ENCODING end - rescue StandardError, NameError - Tk.encoding = 'shiftjis' - Tk.encoding_system = 'shiftjis' + else + tk_enc_name = loc_enc_obj.name + tksys_enc_name = loc_enc_obj.name end - when 'UNICODE' - Tk.encoding = 'unicode' - Tk.encoding_system = 'unicode' - when 'UTF-8' - Tk.encoding = 'utf-8' - Tk.encoding_system = 'utf-8' - else ###### 'ASCII-8BIT' - if defined? DEFAULT_TK_ENCODING - Tk.encoding_system = DEFAULT_TK_ENCODING + else + tk_enc_name = ext_enc_obj.name + tksys_enc_name = ext_enc_obj.name + end + + # Tk.encoding = tk_enc_name + Tk.default_encoding = tk_enc_name + Tk.encoding_system = tksys_enc_name +=end + + if ext_enc_obj == Tk::Encoding::UNKNOWN + if loc_enc_obj == Tk::Encoding::UNKNOWN + # use Tk.encoding_system + else + # use locale_charmap + begin + loc_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(loc_enc_obj) + if loc_enc_name && loc_enc_name != tksys_enc_name + # use locale_charmap + Tk.encoding_system = loc_enc_name + else + # use Tk.encoding_system + end + rescue ArgumentError + # unsupported encoding on Tk -> use Tk.encoding_system + end end + else begin - Tk.encoding = Tk.encoding_system - rescue StandardError, NameError - Tk.encoding = 'utf-8' - Tk.encoding_system = 'utf-8' + ext_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(ext_enc_obj) + if ext_enc_name && ext_enc_name != tksys_enc_name + # use default_external + Tk.encoding_system = ext_enc_name + else + # use Tk.encoding_system + end + rescue ArgumentError + # unsupported encoding on Tk -> use Tk.encoding_system end end - end -else - # dummy methods - class TclTkIp - attr_accessor :encoding + # setup Tk.encoding + enc_name = nil - alias __eval _eval - alias __invoke _invoke + begin + default_def = DEFAULT_TK_ENCODING + if ::Encoding.find(default_def.to_s) != Tk::Encoding::UNKNOWN + enc_name = Tk::Encoding::ENCODING_TABLE.get_name(default_def) + end + rescue NameError + # ignore + enc_name = nil + rescue ArgumentError + enc_name = nil + fail ArgumentError, + "DEFAULT_TK_ENCODING has an unknown encoding #{default_def}" + end - alias _eval_with_enc _eval - alias _invoke_with_enc _invoke + unless enc_name + if ext_enc_obj == Tk::Encoding::UNKNOWN + if loc_enc_obj == Tk::Encoding::UNKNOWN + # use Tk.encoding_system + enc_name = tksys_enc_name + else + # use locale_charmap + begin + loc_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(loc_enc_obj) + if loc_enc_name && loc_enc_name != tksys_enc_name + # use locale_charmap + enc_name = loc_enc_name + else + # use Tk.encoding_system + enc_name = tksys_enc_name + end + rescue ArgumentError + # unsupported encoding on Tk -> use Tk.encoding_system + enc_name = tksys_enc_name + end + end + else + begin + ext_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(ext_enc_obj) + if ext_enc_name && ext_enc_name != tksys_enc_name + # use default_external + enc_name = ext_enc_name + else + # use Tk.encoding_system + enc_name = tksys_enc_name + end + rescue ArgumentError + # unsupported encoding on Tk -> use Tk.encoding_system + enc_name = tksys_enc_name + end + end + end + + Tk.default_encoding = (enc_name)? enc_name: tksys_enc_name end +else + # dummy methods module Tk module Encoding extend Encoding + def force_default_encoding=(mode) + nil + end + + def force_default_encoding? + nil + end + + def default_encoding=(enc) + nil + end + def default_encoding + nil + end + def encoding=(name) nil end @@ -2620,6 +3079,16 @@ else extend Encoding end + + class TclTkIp + attr_accessor :encoding + + alias __eval _eval + alias __invoke _invoke + + alias _eval_with_enc _eval + alias _invoke_with_enc _invoke + end end @@ -2949,6 +3418,14 @@ module TkConfigMethod include TkUtil include TkTreatFont + def TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + @mode || false + end + def TkConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) + fail SecurityError, "can't change the mode" if $SAFE>=4 + @mode = (mode)? true: false + end + def __cget_cmd [self.path, 'cget'] end @@ -3076,7 +3553,7 @@ module TkConfigMethod val end - def cget(slot) + def __cget_core(slot) orig_slot = slot slot = slot.to_s @@ -3152,8 +3629,17 @@ module TkConfigMethod tk_tcl2ruby(tk_call_without_enc(*(__cget_cmd << "-#{slot}")), true) end end + private :__cget_core - def configure(slot, value=None) + def cget(slot) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + __cget_core(slot) + else + __cget_core(slot) rescue nil + end + end + + def __configure_core(slot, value=None) if slot.kind_of? Hash slot = _symbolkey2str(slot) @@ -3216,12 +3702,45 @@ module TkConfigMethod end self end + private :__configure_core + + def __check_available_configure_options(keys) + availables = self.current_configinfo.keys + + # add non-standard keys + availables |= __font_optkeys.map{|k| + [k.to_s, "latin#{k}", "ascii#{k}", "kanji#{k}"] + }.flatten + availables |= __methodcall_optkeys.keys.map{|k| k.to_s} + availables |= __keyonly_optkeys.keys.map{|k| k.to_s} + + keys = _symbolkey2str(keys) + keys.delete_if{|k, v| !(availables.include?(k))} + end + + def configure(slot, value=None) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + __configure_core(slot, value) + else + if slot.kind_of?(Hash) + begin + __configure_core(slot) + rescue + slot = __check_available_configure_options(slot) + __configure_core(slot) unless slot.empty? + end + else + __configure_core(slot, value) rescue nil + end + end + self + end def configure_cmd(slot, value) configure(slot, install_cmd(value)) end - def configinfo(slot = nil) + def __configinfo_core(slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/) @@ -3232,6 +3751,10 @@ module TkConfigMethod conf[__configinfo_struct[:key]][1..-1] if ( ! __configinfo_struct[:alias] \ || conf.size > __configinfo_struct[:alias] + 1 ) + fnt = conf[__configinfo_struct[:default_value]] + if TkFont.is_system_font?(fnt) + conf[__configinfo_struct[:default_value]] = TkNamedFont.new(fnt) + end conf[__configinfo_struct[:current_value]] = fontobj(fontkey) elsif ( __configinfo_struct[:alias] \ && conf.size == __configinfo_struct[:alias] + 1 \ @@ -3568,6 +4091,11 @@ module TkConfigMethod fontconf = ret.assoc(optkey) if fontconf && fontconf.size > 2 ret.delete_if{|inf| inf[0] =~ /^(|latin|ascii|kanji)#{optkey}$/} + fnt = fontconf[__configinfo_struct[:default_value]] + if TkFont.is_system_font?(fnt) + fontconf[__configinfo_struct[:default_value]] \ + = TkNamedFont.new(fnt) + end fontconf[__configinfo_struct[:current_value]] = fontobj(optkey) ret.push(fontconf) end @@ -3592,6 +4120,10 @@ module TkConfigMethod if ( ! __configinfo_struct[:alias] \ || conf.size > __configinfo_struct[:alias] + 1 ) + fnt = conf[__configinfo_struct[:default_value]] + if TkFont.is_system_font?(fnt) + conf[__configinfo_struct[:default_value]] = TkNamedFont.new(fnt) + end conf[__configinfo_struct[:current_value]] = fontobj(fontkey) { conf.shift => conf } elsif ( __configinfo_struct[:alias] \ @@ -3939,6 +4471,11 @@ module TkConfigMethod ret.delete('latin' << optkey) ret.delete('ascii' << optkey) ret.delete('kanji' << optkey) + fnt = fontconf[__configinfo_struct[:default_value]] + if TkFont.is_system_font?(fnt) + fontconf[__configinfo_struct[:default_value]] \ + = TkNamedFont.new(fnt) + end fontconf[__configinfo_struct[:current_value]] = fontobj(optkey) ret[optkey] = fontconf end @@ -3953,6 +4490,19 @@ module TkConfigMethod end end end + private :__configinfo_core + + def configinfo(slot = nil) + if slot && TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + begin + __configinfo_core(slot) + rescue + Array.new(__configinfo_struct.values.max).unshift(slot.to_s) + end + else + __configinfo_core(slot) + end + end def current_configinfo(slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY @@ -4052,7 +4602,12 @@ class TkObject<TkKernel begin cget(name) rescue - super(id, *args) + if self.kind_of?(TkWindow) + fail NameError, + "unknown option '#{id}' for #{self.inspect} (deleted widget?)" + else + super(id, *args) + end # fail NameError, # "undefined local variable or method `#{name}' for #{self.to_s}", # error_at @@ -4107,6 +4662,7 @@ end class TkWindow<TkObject include TkWinfo extend TkBindCore + include Tk::Wm_for_General @@WIDGET_INSPECT_FULL = false def TkWindow._widget_inspect_full_? @@ -4210,7 +4766,20 @@ class TkWindow<TkObject end if keys and keys != None - tk_call_without_enc(cmd, @path, *hash_kv(keys, true)) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + tk_call_without_enc(cmd, @path, *hash_kv(keys, true)) + else + begin + tk_call_without_enc(cmd, @path, *hash_kv(keys, true)) + rescue + 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)) + end + end + end else tk_call_without_enc(cmd, @path) end @@ -4748,7 +5317,7 @@ TkWidget = TkWindow #Tk.freeze module Tk - RELEASE_DATE = '2008-02-29'.freeze + RELEASE_DATE = '2008-03-29'.freeze autoload :AUTO_PATH, 'tk/variable' autoload :TCL_PACKAGE_PATH, 'tk/variable' diff --git a/ext/tk/lib/tk/autoload.rb b/ext/tk/lib/tk/autoload.rb index f7037b403..0773f7708 100644 --- a/ext/tk/lib/tk/autoload.rb +++ b/ext/tk/lib/tk/autoload.rb @@ -93,6 +93,7 @@ module Tk autoload :Scrollable, 'tk/scrollable' autoload :Wm, 'tk/wm' + autoload :Wm_for_General, 'tk/wm' autoload :MacResource, 'tk/macpkg' @@ -159,7 +160,7 @@ autoload :TkWarningObj, 'tk/dialog' autoload :TkEvent, 'tk/event' autoload :TkFont, 'tk/font' -autoload :TkTreatTagFont, 'tk/font' +autoload :TkNamedFont, 'tk/font' autoload :TkImage, 'tk/image' autoload :TkBitmapImage, 'tk/image' @@ -314,11 +315,16 @@ module Tk :TkWinRegistry => 'tk/winpkg', } + @TOPLEVEL_ALIAS_OWNER = {} + @TOPLEVEL_ALIAS_SETUP_PROC = {} @current_default_widget_set = nil end + +############################################ +# methods to control default widget set ############################################ class << Tk @@ -341,7 +347,8 @@ class << Tk @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 @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) end @@ -372,6 +379,7 @@ class << Tk # file => loaded class object Object.const_set(sym, file) end + @TOPLEVEL_ALIAS_OWNER[sym] = target } # update current alias @@ -386,10 +394,11 @@ Tk.default_widget_set = :Tk ############################################ # depend on the version of Tcl/Tk -major, minor, type, type_name, patchlevel = TclTkLib.get_version +# major, minor, type, type_name, patchlevel = TclTkLib.get_version ############################################ # Ttk (Tile) support +=begin if major > 8 || (major == 8 && minor > 5) || (major == 8 && minor == 5 && type >= TclTkLib::RELEASE_TYPE::BETA) @@ -399,3 +408,7 @@ if major > 8 || require 'tk/ttk_selector' end +=end +Object.autoload :Ttk, 'tkextlib/tile' +Tk.autoload :Tile, 'tkextlib/tile' +require 'tk/ttk_selector' diff --git a/ext/tk/lib/tk/bindtag.rb b/ext/tk/lib/tk/bindtag.rb index 9023a08e0..88c8367a8 100644 --- a/ext/tk/lib/tk/bindtag.rb +++ b/ext/tk/lib/tk/bindtag.rb @@ -8,30 +8,64 @@ class TkBindTag #BTagID_TBL = {} BTagID_TBL = TkCore::INTERP.create_table - Tk_BINDTAG_ID = ["btag".freeze, "00000".taint].freeze - TkCore::INTERP.init_ip_env{ BTagID_TBL.clear } + (Tk_BINDTAG_ID = ["btag".freeze, "00000".taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + BTagID_TBL.mutex.synchronize{ BTagID_TBL.clear } + } def TkBindTag.id2obj(id) - BTagID_TBL[id]? BTagID_TBL[id]: id + BTagID_TBL.mutex.synchronize{ + (BTagID_TBL[id])? BTagID_TBL[id]: id + } end +=begin def TkBindTag.new_by_name(name, *args, &b) - return BTagID_TBL[name] if BTagID_TBL[name] + BTagID_TBL.mutex.synchronize{ + return BTagID_TBL[name] if BTagID_TBL[name] + } + self.new.instance_eval{ - BTagID_TBL.delete @id - @id = name - BTagID_TBL[@id] = self + BTagID_TBL.mutex.synchronize{ + BTagID_TBL.delete @id + @id = name + BTagID_TBL[@id] = self + } bind(*args, &b) if args != [] self } end +=end + def TkBindTag.new_by_name(name, *args, &b) + obj = nil + BTagID_TBL.mutex.synchronize{ + if BTagID_TBL[name] + obj = BTagID_TBL[name] + else + (obj = BTagID_TBL[name] = self.allocate).instance_eval{ + @id = name + } + end + } + bind(*args, &b) if obj && args != [] + obj + end def initialize(*args, &b) - # @id = Tk_BINDTAG_ID.join('') - @id = Tk_BINDTAG_ID.join(TkCore::INTERP._ip_id_) - Tk_BINDTAG_ID[1].succ! - BTagID_TBL[@id] = self + Tk_BINDTAG_ID.mutex.synchronize{ + # @id = Tk_BINDTAG_ID.join('') + @id = Tk_BINDTAG_ID.join(TkCore::INTERP._ip_id_) + Tk_BINDTAG_ID[1].succ! + } + BTagID_TBL.mutex.synchronize{ + BTagID_TBL[@id] = self + } bind(*args, &b) if args != [] end @@ -63,14 +97,37 @@ end class TkDatabaseClass<TkBindTag +=begin def self.new(name, *args, &b) - return BTagID_TBL[name] if BTagID_TBL[name] + BTagID_TBL.mutex.synchronize{ + return BTagID_TBL[name] if BTagID_TBL[name] + } super(name, *args, &b) end def initialize(name, *args, &b) @id = name - BTagID_TBL[@id] = self + BTagID_TBL.mutex.synchronize{ + BTagID_TBL[@id] = self + } + bind(*args, &b) if args != [] + end +=end + def self.new(name, *args, &b) + BTagID_TBL.mutex.synchronize{ + if BTagID_TBL[name] + BTagID_TBL[name] + else + BTagID_TBL[name] = self.allocate.instance_eval{ + initialize(name, *args, &b) + self + } + end + } + end + + def initialize(name, *args, &b) + @id = name bind(*args, &b) if args != [] end diff --git a/ext/tk/lib/tk/canvas.rb b/ext/tk/lib/tk/canvas.rb index 4abc99202..fceadd5e9 100644 --- a/ext/tk/lib/tk/canvas.rb +++ b/ext/tk/lib/tk/canvas.rb @@ -185,11 +185,17 @@ class Tk::Canvas<TkWindow end def delete(*args) - if TkcItem::CItemID_TBL[self.path] + tbl = nil + TkcItem::CItemID_TBL.mutex.synchronize{ + tbl = TkcItem::CItemID_TBL[self.path] + } + if tbl args.each{|tag| find('withtag', tag).each{|item| if item.kind_of?(TkcItem) - TkcItem::CItemID_TBL[self.path].delete(item.id) + TkcItem::CItemID_TBL.mutex.synchronize{ + tbl.delete(item.id) + } end } } @@ -584,9 +590,12 @@ class TkcItem<TkObject CItemTypeName = nil CItemTypeToClass = {} + CItemID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ CItemID_TBL.clear } + TkCore::INTERP.init_ip_env{ + CItemID_TBL.mutex.synchronize{ CItemID_TBL.clear } + } def TkcItem.type2class(type) CItemTypeToClass[type] @@ -594,8 +603,13 @@ class TkcItem<TkObject def TkcItem.id2obj(canvas, id) cpath = canvas.path - return id unless CItemID_TBL[cpath] - CItemID_TBL[cpath][id]? CItemID_TBL[cpath][id]: id + CItemID_TBL.mutex.synchronize{ + if CItemID_TBL[cpath] + CItemID_TBL[cpath][id]? CItemID_TBL[cpath][id]: id + else + id + end + } end ######################################## @@ -668,8 +682,10 @@ class TkcItem<TkObject @path = parent.path @id = create_self(*args) # an integer number as 'canvas item id' - CItemID_TBL[@path] = {} unless CItemID_TBL[@path] - CItemID_TBL[@path][@id] = self + CItemID_TBL.mutex.synchronize{ + CItemID_TBL[@path] = {} unless CItemID_TBL[@path] + CItemID_TBL[@path][@id] = self + } end def create_self(*args) self.class.create(@c, *args) # return an integer number as 'canvas item id' @@ -690,7 +706,9 @@ class TkcItem<TkObject def delete @c.delete @id - CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + CItemID_TBL.mutex.synchronize{ + CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + } self end alias remove delete diff --git a/ext/tk/lib/tk/canvastag.rb b/ext/tk/lib/tk/canvastag.rb index a5650ee68..7feea1575 100644 --- a/ext/tk/lib/tk/canvastag.rb +++ b/ext/tk/lib/tk/canvastag.rb @@ -199,14 +199,26 @@ class TkcTag<TkObject include TkcTagAccess CTagID_TBL = TkCore::INTERP.create_table - Tk_CanvasTag_ID = ['ctag'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ CTagID_TBL.clear } + (Tk_CanvasTag_ID = ['ctag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + CTagID_TBL.mutex.synchronize{ CTagID_TBL.clear } + } def TkcTag.id2obj(canvas, id) cpath = canvas.path - return id unless CTagID_TBL[cpath] - CTagID_TBL[cpath][id]? CTagID_TBL[cpath][id]: id + CTagID_TBL.mutex.synchronize{ + if CTagID_TBL[cpath] + CTagID_TBL[cpath][id]? CTagID_TBL[cpath][id]: id + else + id + end + } end def initialize(parent, mode=nil, *args) @@ -215,11 +227,15 @@ class TkcTag<TkObject #end @c = parent @cpath = parent.path - # @path = @id = Tk_CanvasTag_ID.join('') - @path = @id = Tk_CanvasTag_ID.join(TkCore::INTERP._ip_id_) - CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] - CTagID_TBL[@cpath][@id] = self - Tk_CanvasTag_ID[1].succ! + Tk_CanvasTag_ID.mutex.synchronize{ + # @path = @id = Tk_CanvasTag_ID.join('') + @path = @id = Tk_CanvasTag_ID.join(TkCore::INTERP._ip_id_) + Tk_CanvasTag_ID[1].succ! + } + CTagID_TBL.mutex.synchronize{ + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + } if mode tk_call_without_enc(@c.path, "addtag", @id, mode, *args) end @@ -238,7 +254,9 @@ class TkcTag<TkObject def delete @c.delete @id - CTagID_TBL[@cpath].delete(@id) if CTagID_TBL[@cpath] + CTagID_TBL.mutex.synchronize{ + CTagID_TBL[@cpath].delete(@id) if CTagID_TBL[@cpath] + } self end alias remove delete @@ -288,23 +306,38 @@ class TkcTag<TkObject end class TkcTagString<TkcTag - def self.new(parent, name, *args) - if CTagID_TBL[parent.path] && CTagID_TBL[parent.path][name] - return CTagID_TBL[parent.path][name] - else - super(parent, name, *args) + def self.new(parent, name, mode=nil, *args) + obj = nil + CTagID_TBL.mutex.synchronize{ + if CTagID_TBL[parent.path] && CTagID_TBL[parent.path][name] + obj = CTagID_TBL[parent.path][name] + else + # super(parent, name, *args) + (obj = self.allocate).instance_eval{ + @c = parent + @cpath = parent.path + @path = @id = name + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + } + end + } + if obj && mode + tk_call_without_enc(@c.path, "addtag", @id, mode, *args) end + obj end def initialize(parent, name, mode=nil, *args) + # dummy:: not called by 'new' method + #unless parent.kind_of?(TkCanvas) # fail ArgumentError, "expect TkCanvas for 1st argument" #end @c = parent @cpath = parent.path @path = @id = name - CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] - CTagID_TBL[@cpath][@id] = self + if mode tk_call_without_enc(@c.path, "addtag", @id, mode, *args) end @@ -312,7 +345,11 @@ class TkcTagString<TkcTag end TkcNamedTag = TkcTagString -class TkcTagAll<TkcTag +class TkcTagAll<TkcTagString + def self.new(parent) + super(parent, 'all') + end +=begin def initialize(parent) #unless parent.kind_of?(TkCanvas) # fail ArgumentError, "expect TkCanvas for 1st argument" @@ -320,12 +357,19 @@ class TkcTagAll<TkcTag @c = parent @cpath = parent.path @path = @id = 'all' - CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] - CTagID_TBL[@cpath][@id] = self + CTagID_TBL.mutex.synchronize{ + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + } end +=end end -class TkcTagCurrent<TkcTag +class TkcTagCurrent<TkcTagString + def self.new(parent) + super(parent, 'current') + end +=begin def initialize(parent) #unless parent.kind_of?(TkCanvas) # fail ArgumentError, "expect TkCanvas for 1st argument" @@ -333,13 +377,21 @@ class TkcTagCurrent<TkcTag @c = parent @cpath = parent.path @path = @id = 'current' - CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] - CTagID_TBL[@cpath][@id] = self + CTagID_TBL.mutex.synchronize{ + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + } end +=end end class TkcGroup<TkcTag - Tk_cGroup_ID = ['tkcg'.freeze, '00000'.taint].freeze + (Tk_cGroup_ID = ['tkcg'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + #def create_self(parent, *args) def initialize(parent, *args) #unless parent.kind_of?(TkCanvas) @@ -347,11 +399,15 @@ class TkcGroup<TkcTag #end @c = parent @cpath = parent.path - # @path = @id = Tk_cGroup_ID.join('') - @path = @id = Tk_cGroup_ID.join(TkCore::INTERP._ip_id_) - CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] - CTagID_TBL[@cpath][@id] = self - Tk_cGroup_ID[1].succ! + Tk_cGroup_ID.mutex.synchronize{ + # @path = @id = Tk_cGroup_ID.join('') + @path = @id = Tk_cGroup_ID.join(TkCore::INTERP._ip_id_) + Tk_cGroup_ID[1].succ! + } + CTagID_TBL.mutex.synchronize{ + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + } include(*args) if args != [] end #private :create_self diff --git a/ext/tk/lib/tk/encodedstr.rb b/ext/tk/lib/tk/encodedstr.rb index 797e514a4..02de0b0d8 100644 --- a/ext/tk/lib/tk/encodedstr.rb +++ b/ext/tk/lib/tk/encodedstr.rb @@ -70,13 +70,89 @@ module Tk # @encoding = ( enc || # ((self.class::Encoding)? # self.class::Encoding : Tk.encoding_system) ) - @encoding = ( enc || - ((self.class::Encoding)? + enc ||= (self.class::Encoding)? self.class::Encoding : - ((Tk.encoding)? Tk.encoding : Tk.encoding_system) ) ) + ((Tk.encoding)? Tk.encoding : Tk.encoding_system) + if TkCore::WITH_ENCODING + unless encobj = Tk::Encoding::ENCODING_TABLE.get_obj(enc) + fail ArgumentError, "unsupported Tk encoding '#{enc}'" + end + self.force_encoding(encobj) + else + @encoding = enc + end + end + + if TkCore::WITH_ENCODING + alias encoding_obj encoding + alias __encoding encoding + def encoding + Tk::Encoding::ENCODING_TABLE.get_name(super()) + end + else + def encoding + @encoding + end + alias encoding_obj encoding end - attr_reader :encoding + if TkCore::WITH_ENCODING + # wrapper methods for compatibility + alias __instance_variable_get instance_variable_get + alias __instance_variable_set instance_variable_set + alias __instance_eval instance_eval + alias __instance_variables instance_variables + + def instance_variable_get(key) + if (key.to_s == '@encoding') + self.encoding + else + super(key) + end + end + + def instance_variable_set(key, value) + if (key.to_s == '@encoding') + if value + self.force_encoding(value) + else + self.force_encoding(Tk::Encoding::UNKNOWN) + end + value + else + super(key, value) + end + end + + def instance_eval(*args, &b) + old_enc = @encoding = self.encoding + + ret = super(*args, &b) + + if @encoding + if @encoding != old_enc + # modified by user + self.force_encoding(@encoding) + end + remove_instance_variable(:@encoding) + else + begin + remove_instance_variable(:@encoding) + # user sets to nil -> use current default + self.force_encoding(Tk.encoding) + rescue NameError + # removed by user -> ignore, because user don't use @encoding + end + end + ret + end + end + + def instance_variables + ret = super() + ret << :@encoding # fake !! + ret + end end # def Tk.EncodedString(str, enc = nil) # Tk::EncodedString.new(str, enc) diff --git a/ext/tk/lib/tk/event.rb b/ext/tk/lib/tk/event.rb index 9884ca02e..0042fcaa6 100644 --- a/ext/tk/lib/tk/event.rb +++ b/ext/tk/lib/tk/event.rb @@ -15,8 +15,6 @@ require 'tk' module TkEvent class Event < TkUtil::CallbackSubst module Grp - major, minor, type, type_name, patchlevel = TclTkLib.get_version - KEY = 0x1 BUTTON = 0x2 MOTION = 0x4 @@ -43,6 +41,8 @@ module TkEvent MWHEEL = KEY + STRING_DATA = 0x80000000 # special flag for 'data' field + ALL = 0xFFFFFFFF KEY_BUTTON_MOTION_VIRTUAL = (KEY|MWHEEL|BUTTON|MOTION|VIRTUAL) @@ -157,7 +157,7 @@ module TkEvent 'borderwidth' => (Grp::CREATE|Grp::CONFIG), 'button' => Grp::BUTTON, 'count' => Grp::EXPOSE, - 'data' => Grp::VIRTUAL, + 'data' => (Grp::VIRTUAL|Grp::STRING_DATA), 'delta' => Grp::MWHEEL, 'detail' => (Grp::FOCUS|Grp::CROSSING), 'focus' => Grp::CROSSING, @@ -225,7 +225,8 @@ module TkEvent rescue next end - next if !val || val == '??' + # next if !val || val == '??' + next if !val || (val == '??' && (flag & Grp::STRING_DATA)) fields[key] = val } @@ -370,6 +371,22 @@ module TkEvent nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + # setup tables to be used by scan_args, _get_subst_key, _get_all_subst_keys # # _get_subst_key() and _get_all_subst_keys() generates key-string diff --git a/ext/tk/lib/tk/font.rb b/ext/tk/lib/tk/font.rb index 444118e6a..4641d8a64 100644 --- a/ext/tk/lib/tk/font.rb +++ b/ext/tk/lib/tk/font.rb @@ -11,13 +11,18 @@ class TkFont TkCommandNames = ['font'.freeze].freeze - Tk_FontID = ["@font".freeze, "00000".taint].freeze + (Tk_FontID = ["@font".freeze, "00000".taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + Tk_FontNameTBL = TkCore::INTERP.create_table Tk_FontUseTBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ - Tk_FontNameTBL.clear - Tk_FontUseTBL.clear + Tk_FontNameTBL.mutex.synchronize{ Tk_FontNameTBL.clear } + Tk_FontUseTBL.mutex.synchronize{ Tk_FontUseTBL.clear } } # option_type : default => string @@ -31,13 +36,26 @@ class TkFont MetricType = Hash.new(?n) MetricType['fixed'] = ?b + # system font names + SYSTEM_FONT_NAMES = [] + def SYSTEM_FONT_NAMES.add(font_names) + (@mutex ||= Mutex.new).synchronize{ + self.replace(self | font_names.map{|name| name.to_s}) + } + end + def SYSTEM_FONT_NAMES.include?(name) + (@mutex ||= Mutex.new).synchronize{ + super(name.to_s) + } + end + # set default font case Tk::TK_VERSION - when /^4\.*/ + when /^4\..*/ DEFAULT_LATIN_FONT_NAME = 'a14'.freeze DEFAULT_KANJI_FONT_NAME = 'k14'.freeze - when /^8\.*/ + when /^8\.[0-4]/ if JAPANIZED_TK begin fontnames = tk_call('font', 'names') @@ -103,6 +121,15 @@ class TkFont DEFAULT_LATIN_FONT_NAME = ltn.freeze DEFAULT_KANJI_FONT_NAME = knj.freeze + when /^8\.[5-9]/, /^9\..*/ + if tk_call('font', 'names') =~ /\bTkDefaultFont\b/ + DEFAULT_LATIN_FONT_NAME = 'TkDefaultFont'.freeze + DEFAULT_KANJI_FONT_NAME = 'TkDefaultFont'.freeze + else + DEFAULT_LATIN_FONT_NAME = 'Helvetica'.freeze + DEFAULT_KANJI_FONT_NAME = 'mincho'.freeze + end + else # unknown version DEFAULT_LATIN_FONT_NAME = 'Helvetica'.freeze DEFAULT_KANJI_FONT_NAME = 'mincho'.freeze @@ -121,6 +148,7 @@ class TkFont unless compound.kind_of?(TkFont) fail ArgumentError, "a TkFont object is expected for the 1st argument" end + @compound = compound case type when 'kanji', 'latin', 'ascii' @@ -145,6 +173,9 @@ class TkFont def font @compound.__send__(@type + '_font_id') end + alias font_id font + alias name font + alias to_s font def [](slot) @compound.__send__(@type + '_configinfo', slot) @@ -163,6 +194,14 @@ class TkFont ################################### # class methods ################################### + def TkFont.is_system_font?(fnt) + # true --> system font which is available on the current system + # false --> not system font (or unknown system font) + # nil --> system font name, but not available on the current system + fnt = fnt.to_s + SYSTEM_FONT_NAMES.include?(fnt) && self.names.index(fnt) && true + end + def TkFont.actual(fnt, option=nil) fnt = '{}' if fnt == '' if fnt.kind_of?(TkFont) @@ -171,6 +210,9 @@ class TkFont actual_core(fnt, nil, option) end end + def TkFont.actual_hash(fnt, option=nil) + Hash[TkFont.actual_hash(fnt, option)] + end def TkFont.actual_displayof(fnt, win, option=nil) fnt = '{}' if fnt == '' @@ -181,6 +223,9 @@ class TkFont actual_core(fnt, win, option) end end + def TkFont.actual_hash_displayof(fnt, option=nil) + Hash[TkFont.actual_hash_displayof(fnt, option)] + end def TkFont.configure(fnt, slot, value=None) if fnt.kind_of?(TkFont) @@ -234,6 +279,33 @@ class TkFont metrics_core(fnt, nil, option) end end + def TkFont.metrics_hash(fnt, option=nil) + if option + val = TkFont.metrics(fnt, option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[TkFont.metrics(fnt)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h + end def TkFont.metrics_displayof(fnt, win, option=nil) fnt = '{}' if fnt == '' @@ -244,13 +316,40 @@ class TkFont metrics_core(fnt, win, option) end end + def TkFont.metrics_hash_displayof(fnt, win, option=nil) + if option + val = TkFont.metrics_displayof(fnt, win, option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[TkFont.metrics_displayof(fnt, win, option)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h + end def TkFont.families(win=nil) case (Tk::TK_VERSION) - when /^4\.*/ + when /^4\..*/ ['fixed'] - when /^8\.*/ + when /^8\..*/ if win tk_split_simplelist(tk_call('font', 'families', '-displayof', win)) else @@ -261,13 +360,16 @@ class TkFont def TkFont.names case (Tk::TK_VERSION) - when /^4\.*/ + when /^4\..*/ r = ['fixed'] r += ['a14', 'k14'] if JAPANIZED_TK - Tk_FontNameTBL.each_value{|obj| r.push(obj)} - r | [] + Tk_FontNameTBL.mutex.synchronize{ + Tk_FontNameTBL.each_value{|obj| r.push(obj)} + } + #r | [] + r.uniq - when /^8\.*/ + when /^8\..*/ tk_split_simplelist(tk_call('font', 'names')) end @@ -285,10 +387,15 @@ class TkFont end def TkFont.get_obj(name) + name = name.to_s if name =~ /^(@font[0-9]+)(|c|l|k)$/ - Tk_FontNameTBL[$1] + Tk_FontNameTBL.mutex.synchronize{ + Tk_FontNameTBL[$1] + } else - nil + Tk_FontNameTBL.mutex.synchronize{ + Tk_FontNameTBL[name] + } end end @@ -298,7 +405,7 @@ class TkFont path = [win, tag, key].join(';') case (Tk::TK_VERSION) - when /^4\.*/ + when /^4\..*/ regexp = /^-(|kanji)#{key} / conf_list = tk_split_simplelist(tk_call(*args)). @@ -324,7 +431,7 @@ class TkFont TkFont.new(ltn, knj).call_font_configure([path, key], *args) - when /^8\.*/ + when /^8\.[0-4]/ regexp = /^-#{key} / conf_list = tk_split_simplelist(tk_call(*args)). @@ -360,26 +467,66 @@ class TkFont compound = [] end if compound == [] - TkFont.new(fnt).call_font_configure([path, key], *args) + if TkFont.is_system_font?(fnt) + TkNamedFont.new(fnt).call_font_configure([path, key], *args) + else + TkFont.new(fnt).call_font_configure([path, key], *args) + end else TkFont.new(compound[0], compound[1]).call_font_configure([path, key], *args) end end + + when /^8\.[5-9]/, /^9\..*/ + regexp = /^-#{key} / + + conf_list = tk_split_simplelist(tk_call(*args)). + find_all{|prop| prop =~ regexp}. + collect{|prop| tk_split_simplelist(prop)} + + if conf_list.size == 0 + raise RuntimeError, "the widget may not support 'font' option" + end + + args << {} + + optkey = "-#{key}" + + info = conf_list.find{|conf| conf[0] == optkey} + fnt = info[-1] + fnt = nil if fnt == [] || fnt == "" + + unless fnt + # create dummy + # TkFont.new(nil, nil).call_font_configure([path, key], *args) + dummy_fnt = TkFont.allocate + dummy_fnt.instance_eval{ init_dummy_fontobj() } + dummy_fnt + else + if TkFont.is_system_font?(fnt) + TkNamedFont.new(fnt).call_font_configure([path, key], *args) + else + TkFont.new(fnt).call_font_configure([path, key], *args) + end + end end end def TkFont.used_on(path=nil) - if path - Tk_FontUseTBL[path] - else - Tk_FontUseTBL.values | [] - end + Tk_FontUseTBL.mutex.synchronize{ + if path + Tk_FontUseTBL[path] + else + # Tk_FontUseTBL.values | [] + Tk_FontUseTBL.values.uniq + end + } end def TkFont.failsafe(font) begin - if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK + if /^8\..*/ === Tk::TK_VERSION && JAPANIZED_TK tk_call('font', 'failsafe', font) end rescue @@ -392,15 +539,20 @@ class TkFont private ################################### def init_dummy_fontobj - @id = Tk_FontID.join(TkCore::INTERP._ip_id_) - Tk_FontID[1].succ! - Tk_FontNameTBL[@id] = self + Tk_FontID.mutex.synchronize{ + @id = Tk_FontID.join(TkCore::INTERP._ip_id_) + Tk_FontID[1].succ! + } + Tk_FontNameTBL.mutex.synchronize{ + Tk_FontNameTBL[@id] = self + } - @latin_desscendant = nil - @kanji_desscendant = nil + # @latin_desscendant = nil + # @kanji_desscendant = nil + @descendant = [nil, nil] # [latin, kanji] case (Tk::TK_VERSION) - when /^4\.*/ + when /^4\..*/ @latinfont = "" @kanjifont = "" if JAPANIZED_TK @@ -436,13 +588,23 @@ class TkFont ltn = '{}' if ltn == '' knj = '{}' if knj == '' - # @id = Tk_FontID.join('') - @id = Tk_FontID.join(TkCore::INTERP._ip_id_) - Tk_FontID[1].succ! - Tk_FontNameTBL[@id] = self + Tk_FontID.mutex.synchronize{ + # @id = Tk_FontID.join('') + @id = Tk_FontID.join(TkCore::INTERP._ip_id_) + Tk_FontID[1].succ! + } + Tk_FontNameTBL.mutex.synchronize{ + Tk_FontNameTBL[@id] = self + } + + # @latin_desscendant = nil + # @kanji_desscendant = nil + @descendant = [nil, nil] # [latin, kanji] - @latin_desscendant = nil - @kanji_desscendant = nil + # @latinfont = @id + 'l' + # @kanjifont = @id + 'k' + # @compoundfont = @id + 'c' + # @fontslot = {} if knj.kind_of?(Hash) && !keys keys = knj @@ -474,7 +636,7 @@ class TkFont if ltn if JAPANIZED_TK && !knj - if Tk::TK_VERSION =~ /^4.*/ + if Tk::TK_VERSION =~ /^4..*/ knj = DEFAULT_KANJI_FONT_NAME else knj = ltn @@ -625,9 +787,14 @@ class TkFont if JAPANIZED_TK @compoundfont = [[@latinfont], [@kanjifont]] @fontslot = {'font'=>@latinfont, 'kanjifont'=>@kanjifont} + # @fontslot.clear + # @fontslot['font'] = @latinfont + # @fontslot['kanjifont'] = @kanjifont else @compoundfont = @latinfont @fontslot = {'font'=>@latinfont} + # @fontslot.clear + # @fontslot['font'] = @latinfont end end @@ -753,6 +920,7 @@ class TkFont end @fontslot = {'font'=>@compoundfont} + # @fontslot['font'] = @compoundfont begin tk_call('font', 'create', @compoundfont, '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) @@ -833,6 +1001,7 @@ class TkFont end @fontslot = {'font'=>@compoundfont} + # @fontslot['font'] = @compoundfont tk_call('font', 'configure', @compoundfont, *hash_kv(keys)) end end @@ -888,13 +1057,19 @@ class TkFont keys = _symbolkey2str(args.pop).update(fontslot) args.concat(hash_kv(keys)) tk_call(*args) - Tk_FontUseTBL[[win, tag, optkey].join(';')] = self + Tk_FontUseTBL.mutex.synchronize{ + Tk_FontUseTBL[[win, tag, optkey].join(';')] = self + } self end def used ret = [] - Tk_FontUseTBL.each{|key,value| + table = nil + Tk_FontUseTBL.mutex.synchronize{ + table = Tk_FontUseTBL.clone # to avoid deadlock + } + table.each{|key,value| next unless self == value if key.include?(';') win, tag, optkey = key.split(';') @@ -960,6 +1135,8 @@ class TkFont @compoundfont end alias font_id font + alias name font + alias to_s font def latin_font_id @latinfont @@ -967,11 +1144,18 @@ class TkFont def latin_font # @latinfont + if @descendant[0] # [0] -> latin + @descendant[0] + else + @descendant[0] = DescendantFont.new(self, 'latin') + end +=begin if @latin_descendant @latin_descendant else @latin_descendant = DescendantFont.new(self, 'latin') end +=end end alias latinfont latin_font @@ -981,50 +1165,87 @@ class TkFont def kanji_font # @kanjifont + if @descendant[1] # [1] -> kanji + @descendant[1] + else + @descendant[1] = DescendantFont.new(self, 'kanji') + end +=begin if @kanji_descendant @kanji_descendant else @kanji_descendant = DescendantFont.new(self, 'kanji') end +=end end alias kanjifont kanji_font def actual(option=nil) actual_core(@compoundfont, nil, option) end + def actual_hash(option=nil) + Hash[actual(option)] + end def actual_displayof(win, option=nil) win = '.' unless win actual_core(@compoundfont, win, option) end + def actual_hash_displayof(win, option=nil) + Hash[actual_displayof(win, option)] + end def latin_actual(option=nil) - actual_core(@latinfont, nil, option) + if @latinfont == nil + actual_core(@compoundfont, nil, option) # use @compoundfont + else + actual_core(@latinfont, nil, option) + end + end + def latin_actual_hash(option=nil) + Hash[latin_actual(option)] end def latin_actual_displayof(win, option=nil) win = '.' unless win - actual_core(@latinfont, win, option) + if @latinfont == nil + actual_core(@compoundfont, win, option) # use @compoundfont + else + actual_core(@latinfont, win, option) + end + end + def latin_actual_hash_displayof(win, option=nil) + Hash[latin_actual_displayof(win, option)] end def kanji_actual(option=nil) #if JAPANIZED_TK - if @kanjifont != "" + if @kanjifont == nil + actual_core(@compoundfont, nil, option) # use @compoundfont + elsif @kanjifont != "" actual_core(@kanjifont, nil, option) else actual_core_tk4x(nil, nil, option) end end + def kanji_actual_hash(option=nil) + Hash[kanji_actual(option)] + end def kanji_actual_displayof(win, option=nil) #if JAPANIZED_TK - if @kanjifont != "" + if @kanjifont == nil + actual_core(@compoundfont, nil, option) # use @compoundfont + elsif @kanjifont != "" win = '.' unless win actual_core(@kanjifont, win, option) else actual_core_tk4x(nil, win, option) end end + def kanji_actual_hash_displayof(win, option=nil) + Hash[kanji_actual_displayof(win, option)] + end def [](slot) configinfo slot @@ -1068,10 +1289,15 @@ class TkFont configinfo(slot) end end + def latin_current_configinfo(slot=nil) + Hash[latin_configinfo(slot)] + end def kanji_configure(slot, value=None) #if JAPANIZED_TK - if @kanjifont != "" + if @kanjifont == nil + configure_core(@compoundfont, slot, value) # use @compoundfont + elsif @kanjifont != "" configure_core(@kanjifont, slot, value) configure('size'=>configinfo('size')) # to reflect new configuration else @@ -1083,13 +1309,18 @@ class TkFont def kanji_configinfo(slot=nil) #if JAPANIZED_TK - if @kanjifont != "" + if @kanjifont == nil + configure_core(@compoundfont, slot) # use @compoundfont + elsif @kanjifont != "" configinfo_core(@kanjifont, slot) else #[] configinfo(slot) end end + def kanji_current_configinfo(slot=nil) + Hash[kanji_configinfo(slot)] + end def replace(ltn, knj=None) knj = ltn if knj == None @@ -1099,12 +1330,30 @@ class TkFont end def latin_replace(ltn) - latin_replace_core(ltn) - reset_pointadjust + if @latinfont + latin_replace_core(ltn) + reset_pointadjust + else + # not compound font -> copy properties of ltn + latinkeys = {} + begin + actual_core(ltn).each{|key,val| latinkeys[key] = val} + rescue + latinkeys = {} + end + begin + tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys)) + rescue + # not exist? (deleted?) -> create font + tk_call('font', 'create', @compoundfont, *hash_kv(latinkeys)) + end + end + self end def kanji_replace(knj) + return self unless @kanjifont # ignore kanji_replace_core(knj) reset_pointadjust self @@ -1122,41 +1371,215 @@ class TkFont def metrics(option=nil) metrics_core(@compoundfont, nil, option) end + def metrics_hash(option=nil) + if option + val = metrics(option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[metrics(option)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h + end def metrics_displayof(win, option=nil) win = '.' unless win metrics_core(@compoundfont, win, option) end + def metrics_hash_displayof(win, option=nil) + if option + val = metrics_displayof(win, option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[metrics_displayof(win, option)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h + end def latin_metrics(option=nil) - metrics_core(@latinfont, nil, option) + if @latinfont == nil + metrics_core(@compoundfont, nil, option) # use @compoundfont + else + metrics_core(@latinfont, nil, option) + end + end + def latin_metrics_hash(option=nil) + if option + val = latin_metrics(option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[latin_metrics(option)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h end def latin_metrics_displayof(win, option=nil) win = '.' unless win - metrics_core(@latinfont, win, option) + if @latinfont == nil + metrics_core(@compoundfont, win, option) # use @compoundfont + else + metrics_core(@latinfont, win, option) + end + end + def latin_metrics_hash_displayof(win, option=nil) + if option + val = latin_metrics_displayof(win, option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[latin_metrics_displayof(win, option)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h end def kanji_metrics(option=nil) - if JAPANIZED_TK + if @latinfont == nil + metrics_core(@compoundfont, nil, option) # use @compoundfont + elsif JAPANIZED_TK metrics_core(@kanjifont, nil, option) else metrics_core_tk4x(nil, nil, option) end end + def kanji_metrics_hash(option=nil) + if option + val = kanji_metrics(option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[kanji_metrics(option)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h + end def kanji_metrics_displayof(win, option=nil) - if JAPANIZED_TK - win = '.' unless win + win = '.' unless win + if @latinfont == nil + metrics_core(@compoundfont, win, option) # use @compoundfont + elsif JAPANIZED_TK metrics_core(@kanjifont, win, option) else metrics_core_tk4x(nil, win, option) end end + def kanji_metrics_hash_displayof(win, option=nil) + if option + val = kanji_metrics_displayof(win, option) + case TkFont::MetricsType[option.to_s] + when ?n + val = TkComm::num_or_str(val) + when ?b + val = TkComm::bool(val) + else + # do nothing + end + return val + end + + h = Hash[kanji_metrics_displayof(win, option)] + h.keys.each{|k| + case TkFont::MetricsType[k.to_s] + when ?n + h[k] = TkComm::num_or_str(h[k]) + when ?b + h[k] = TkComm::bool(h[k]) + else + # do nothing + end + } + h + end def reset_pointadjust begin - if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK + if /^8\..*/ === Tk::TK_VERSION && JAPANIZED_TK configure('pointadjust' => latin_actual.assoc('size')[1].to_f / kanji_actual.assoc('size')[1].to_f ) end @@ -1169,7 +1592,7 @@ class TkFont # private alias ################################### case (Tk::TK_VERSION) - when /^4\.*/ + when /^4\..*/ alias create_latinfont create_latinfont_tk4x alias create_kanjifont create_kanjifont_tk4x alias create_compoundfont create_compoundfont_tk4x @@ -1474,32 +1897,44 @@ module TkFont::CoreMethods end def delete_core_tk4x - TkFont::Tk_FontNameTBL.delete(@id) - TkFont::Tk_FontUseTBL.delete_if{|key,value| value == self} + TkFont::Tk_FontNameTBL.mutex.synchronize{ + TkFont::Tk_FontNameTBL.delete(@id) + } + TkFont::Tk_FontUseTBL.mutex.synchronize{ + TkFont::Tk_FontUseTBL.delete_if{|key,value| value == self} + } end def delete_core_tk8x begin - tk_call('font', 'delete', @latinfont) + tk_call('font', 'delete', @latinfont) if @latinfont rescue end begin - tk_call('font', 'delete', @kanjifont) + tk_call('font', 'delete', @kanjifont) if @kanjifont rescue end begin - tk_call('font', 'delete', @compoundfont) + tk_call('font', 'delete', @compoundfont) if @compoundfont rescue end - TkFont::Tk_FontNameTBL.delete(@id) - TkFont::Tk_FontUseTBL.delete_if{|key,value| value == self} + TkFont::Tk_FontNameTBL.mutex.synchronize{ + TkFont::Tk_FontNameTBL.delete(@id) + } + TkFont::Tk_FontUseTBL.mutex.synchronize{ + TkFont::Tk_FontUseTBL.delete_if{|key,value| value == self} + } end def latin_replace_core_tk4x(ltn) create_latinfont_tk4x(ltn) @compoundfont[0] = [@latinfont] if JAPANIZED_TK @fontslot['font'] = @latinfont - TkFont::Tk_FontUseTBL.dup.each{|w, fobj| + table = nil + TkFont::Tk_FontUseTBL.mutex.synchronize{ + table = TkFont::Tk_FontUseTBL.clone + } + table.each{|w, fobj| if self == fobj begin if w.include?(';') @@ -1524,7 +1959,9 @@ module TkFont::CoreMethods tk_call(w, 'configure', '-font', @latinfont) end rescue - TkFont::Tk_FontUseTBL.delete(w) + TkFont::Tk_FontUseTBL.mutex.synchronize{ + TkFont::Tk_FontUseTBL.delete(w) + } end end } @@ -1537,7 +1974,11 @@ module TkFont::CoreMethods create_kanjifont_tk4x(knj) @compoundfont[1] = [@kanjifont] @fontslot['kanjifont'] = @kanjifont - TkFont::Tk_FontUseTBL.dup.each{|w, fobj| + table = nil + TkFont::Tk_FontUseTBL.mutex.synchronize{ + table = TkFont::Tk_FontUseTBL.clone + } + table.dup.each{|w, fobj| if self == fobj begin if w.include?(';') @@ -1562,7 +2003,9 @@ module TkFont::CoreMethods tk_call(w, 'configure', '-kanjifont', @kanjifont) end rescue - TkFont::Tk_FontUseTBL.delete(w) + Tk_FontUseTBL.mutex.synchronize{ + TkFont::Tk_FontUseTBL.delete(w) + } end end } @@ -1627,8 +2070,11 @@ module TkFont::CoreMethods rescue latinkeys = {} end - if latinkeys != {} + begin tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys)) + rescue + # not exist? (deleted?) -> create font + tk_call('font', 'create', @compoundfont, *hash_kv(latinkeys)) end end self @@ -1720,6 +2166,13 @@ module TkFont::CoreMethods r = [] while key=l.shift r.push [key[1..-1], l.shift.to_i] +=begin + if key == '-fixed' # boolean value + r.push [key[1..-1], bool(l.shift)] + else + r.push [key[1..-1], l.shift.to_i] + end +=end end r end @@ -1729,7 +2182,7 @@ module TkFont::CoreMethods # private alias ################################### case (Tk::TK_VERSION) - when /^4\.*/ + when /^4\..*/ alias actual_core actual_core_tk4x alias configure_core configure_core_tk4x alias configinfo_core configinfo_core_tk4x @@ -1769,3 +2222,117 @@ class TkFont include TkFont::CoreMethods extend TkFont::CoreMethods end + +class TkNamedFont < TkFont + # for built-in named fonts + def TkNamedFont.find(name) + name = name.to_s + unless (obj = Tk_FontNameTBL[name]) + obj = self.new(name) if TkFont.is_system_font?(name) + end + obj + end + + def TkNamedFont.new(name, keys=nil) + name = name.to_s + obj = nil + Tk_FontNameTBL.mutex.synchronize{ + unless (obj = Tk_FontNameTBL[name]) + (obj = self.allocate).instance_eval{ + @id = @compoundfont = name.to_s + @latinfont = nil + @kanjifont = nil + @descendant = [self, self] # [latin, kanji] : dummy + Tk_FontNameTBL[@id] = self + } + end + } + obj.instance_eval{ initialize(name, keys) } + obj + end + + ########################### + private + ########################### + def initialize(name, keys=nil) + @id = @compoundfont = name.to_s + + # if not exist named font, create it. + begin + if keys + tk_call('font', 'configure', @compoundfont, keys) + else + tk_call('font', 'configure', @compoundfont) + end + rescue + # the named font doesn't exist -> create + if keys + tk_call('font', 'create', @compoundfont, keys) + else + tk_call('font', 'create', @compoundfont) + end + end + end + + def create_latinfont(fnt) + # ignore + end + def create_kanjifont(fnt) + # ignore + end + def create_compoundfont(ltn, knj, keys) + # ignore + end + + ########################### + public + ########################### + def latin_font_id + @compoundfont + end + def kanji_font_id + @compoundfont + end +end + +####################################### +# define system font names +####################################### +if Tk::TCL_MAJOR_VERSION > 8 || + (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5) + # add standard fonts of Tcl/Tk 8.5+ + TkFont::SYSTEM_FONT_NAMES.add [ + 'TkDefaultFont', 'TkTextFont', 'TkFixedFont', 'TkMenuFont', + 'TkHeadingFont', 'TkCaptionFont', 'TkSmallCaptionFont', + 'TkIconFont', 'TkTooltipFont' + ] +end + +# platform-specific fonts +# -- windows +TkFont::SYSTEM_FONT_NAMES.add [ + 'ansifixed', 'ansi', 'device', 'oemfixed', 'systemfixed', 'system' +] + +# -- macintosh, macosx +TkFont::SYSTEM_FONT_NAMES.add ['system', 'application'] + +if Tk::TCL_MAJOR_VERSION > 8 || + (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5) + TkFont::SYSTEM_FONT_NAMES.add ['menu'] +end + +# -- macosx (Aqua theme) +if Tk::TCL_MAJOR_VERSION > 8 || + (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5) + TkFont::SYSTEM_FONT_NAMES.add [ + 'systemSystemFont', 'systemEmphasizedSystemFont', + 'systemSmallSystemFont', 'systemSmallEmphasizedSystemFont', + 'systemApplicationFont', 'systemLabelFont', 'systemViewsFont', + 'systemMenuTitleFont', 'systemMenuItemFont', 'systemMenuItemMarkFont', + 'systemMenuItemCmdKeyFont', 'systemWindowTitleFont', + 'systemPushButtonFont', 'systemUtilityWindowTitleFont', + 'systemAlertHeaderFont', 'systemToolbarFont', 'systemMiniSystemFont', + 'systemDetailSystemFont', 'systemDetailEmphasizedSystemFont' + ] +end diff --git a/ext/tk/lib/tk/image.rb b/ext/tk/lib/tk/image.rb index 35e2c4e39..57f82cb81 100644 --- a/ext/tk/lib/tk/image.rb +++ b/ext/tk/lib/tk/image.rb @@ -10,9 +10,16 @@ class TkImage<TkObject TkCommandNames = ['image'.freeze].freeze Tk_IMGTBL = TkCore::INTERP.create_table - Tk_Image_ID = ['i'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ Tk_IMGTBL.clear } + (Tk_Image_ID = ['i'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + Tk_IMGTBL.mutex.synchronize{ Tk_IMGTBL.clear } + } def self.new(keys=nil) if keys.kind_of?(Hash) @@ -27,7 +34,10 @@ class TkImage<TkObject obj = name else name = _get_eval_string(name) - obj = Tk_IMGTBL[name] + obj = nil + Tk_IMGTBL.mutex.synchronize{ + obj = Tk_IMGTBL[name] + } end if obj if !(keys[:without_creating] || keys['without_creating']) @@ -43,7 +53,13 @@ class TkImage<TkObject end end end - super(keys) + (obj = self.allocate).instance_eval{ + Tk_IMGTBL.mutex.synchronize{ + initialize(keys) + Tk_IMGTBL[@path] = self + } + } + obj end def initialize(keys=nil) @@ -55,19 +71,22 @@ class TkImage<TkObject without_creating = keys.delete('without_creating') end unless @path - # @path = Tk_Image_ID.join('') - @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_) - Tk_Image_ID[1].succ! + Tk_Image_ID.mutex.synchronize{ + # @path = Tk_Image_ID.join('') + @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_) + Tk_Image_ID[1].succ! + } end unless without_creating tk_call_without_enc('image', 'create', @type, @path, *hash_kv(keys, true)) end - Tk_IMGTBL[@path] = self end def delete - Tk_IMGTBL.delete(@id) if @id + Tk_IMGTBL.mutex.synchronize{ + Tk_IMGTBL.delete(@id) if @id + } tk_call_without_enc('image', 'delete', @path) self end @@ -85,8 +104,10 @@ class TkImage<TkObject end def TkImage.names - Tk.tk_call_without_enc('image', 'names').split.collect!{|id| - (Tk_IMGTBL[id])? Tk_IMGTBL[id] : id + Tk_IMGTBL.mutex.synchronize{ + Tk.tk_call_without_enc('image', 'names').split.collect!{|id| + (Tk_IMGTBL[id])? Tk_IMGTBL[id] : id + } } end diff --git a/ext/tk/lib/tk/itemconfig.rb b/ext/tk/lib/tk/itemconfig.rb index a7885e74f..dbc45a9e7 100644 --- a/ext/tk/lib/tk/itemconfig.rb +++ b/ext/tk/lib/tk/itemconfig.rb @@ -115,6 +115,14 @@ module TkItemConfigMethod include TkTreatItemFont include TkItemConfigOptkeys + def TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + @mode || false + end + def TkItemConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) + fail SecurityError, "can't change the mode" if $SAFE>=4 + @mode = (mode)? true: false + end + def __item_cget_cmd(id) # maybe need to override [self.path, 'itemcget', id] @@ -149,7 +157,7 @@ module TkItemConfigMethod ################################################ - def itemcget(tagOrId, option) + def __itemcget_core(tagOrId, option) orig_opt = option option = option.to_s @@ -224,8 +232,27 @@ module TkItemConfigMethod tk_tcl2ruby(tk_call_without_enc(*(__item_cget_cmd(tagid(tagOrId)) << "-#{option}")), true) end end + private :__itemcget_core - def itemconfigure(tagOrId, slot, value=None) + def itemcget(tagOrId, option) + unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + __itemcget_core(tagOrId, option) + else + begin + __itemcget_core(tagOrId, option) + rescue => e + begin + __itemconfiginfo_core(tagOrId) + # not tag error -> option is unknown + nil + rescue + fail e # tag error + end + end + end + end + + def __itemconfigure_core(tagOrId, slot, value=None) if slot.kind_of? Hash slot = _symbolkey2str(slot) @@ -288,6 +315,48 @@ module TkItemConfigMethod end self end + private :__itemconfigure_core + + def __check_available_itemconfigure_options(tagOrId, keys) + id = tagid(tagOrId) + availables = self.current_itemconfiginfo(id).keys + + # add non-standard keys + availables |= __font_optkeys.map{|k| + [k.to_s, "latin#{k}", "ascii#{k}", "kanji#{k}"] + }.flatten + availables |= __item_methodcall_optkeys(id).keys.map{|k| k.to_s} + availables |= __item_keyonly_optkeys(id).keys.map{|k| k.to_s} + + keys = _symbolkey2str(keys) + keys.delete_if{|k, v| !(availables.include?(k))} + end + + def itemconfigure(tagOrId, slot, value=None) + unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + __itemconfigure_core(tagOrId, slot, value) + else + if slot.kind_of?(Hash) + begin + __itemconfigure_core(tagOrId, slot) + rescue + slot = __check_available_configure_options(tagOrId, slot) + __itemconfigure_core(tagOrId, slot) unless slot.empty? + end + else + begin + __itemconfigure_core(tagOrId, slot, value) + rescue => e + begin + __itemconfiginfo_core(tagOrId) + rescue + fail e # tag error + end + end + end + end + self + end def __itemconfiginfo_core(tagOrId, slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY @@ -299,6 +368,10 @@ module TkItemConfigMethod conf[__item_configinfo_struct(tagid(tagOrId))[:key]][1..-1] if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \ || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) + fnt = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] + if TkFont.is_system_font?(fnt) + conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt) + end conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), fontkey) elsif ( __item_configinfo_struct(tagid(tagOrId))[:alias] \ && conf.size == __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 \ @@ -635,6 +708,10 @@ module TkItemConfigMethod fontconf = ret.assoc(optkey) if fontconf && fontconf.size > 2 ret.delete_if{|inf| inf[0] =~ /^(|latin|ascii|kanji)#{optkey}$/} + fnt = fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] + if TkFont.is_system_font?(fnt) + fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt) + end fontconf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), optkey) ret.push(fontconf) end @@ -658,7 +735,11 @@ module TkItemConfigMethod if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \ || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) - conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = fontobj(tagid(tagOrId), fontkey) + fnt = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] + if TkFont.is_system_font?(fnt) + conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt) + end + conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), fontkey) { conf.shift => conf } elsif ( __item_configinfo_struct(tagid(tagOrId))[:alias] \ && conf.size == __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) @@ -1006,6 +1087,10 @@ module TkItemConfigMethod ret.delete('latin' << optkey) ret.delete('ascii' << optkey) ret.delete('kanji' << optkey) + fnt = fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] + if TkFont.is_system_font?(fnt) + fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt) + end fontconf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), optkey) ret[optkey] = fontconf end @@ -1023,7 +1108,21 @@ module TkItemConfigMethod private :__itemconfiginfo_core def itemconfiginfo(tagOrId, slot = nil) - __itemconfiginfo_core(tagOrId, slot) + if slot && TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + begin + __itemconfiginfo_core(tagOrId, slot) + rescue => e + begin + __itemconfiginfo_core(tagOrId) + # not tag error -> option is unknown + Array.new(__item_configinfo_struct.values.max).unshift(slot.to_s) + rescue + fail e # tag error + end + end + else + __itemconfiginfo_core(tagOrId, slot) + end end def current_itemconfiginfo(tagOrId, slot = nil) diff --git a/ext/tk/lib/tk/menu.rb b/ext/tk/lib/tk/menu.rb index e44f0e3ff..8ba315629 100644 --- a/ext/tk/lib/tk/menu.rb +++ b/ext/tk/lib/tk/menu.rb @@ -202,6 +202,9 @@ class Tk::Menu<TkWindow tk_send_without_enc('unpost') self end + def xposition(index) + number(tk_send_without_enc('xposition', _get_eval_enc_str(index))) + end def yposition(index) number(tk_send_without_enc('yposition', _get_eval_enc_str(index))) end @@ -503,9 +506,24 @@ class Tk::Menubutton<Tk::Label WidgetClassNames[WidgetClassName] = self def create_self(keys) if keys and keys != None - # tk_call_without_enc('menubutton', @path, *hash_kv(keys, true)) - tk_call_without_enc(self.class::TkCommandNames[0], @path, - *hash_kv(keys, true)) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + # tk_call_without_enc('menubutton', @path, *hash_kv(keys, true)) + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + else + begin + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + rescue + tk_call_without_enc(self.class::TkCommandNames[0], @path) + keys = __check_available_configure_options(keys) + unless keys.empty? + tk_call_without_enc('destroy', @path) + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + end + end + end else # tk_call_without_enc('menubutton', @path) tk_call_without_enc(self.class::TkCommandNames[0], @path) @@ -612,6 +630,9 @@ class Tk::OptionMenubutton<Tk::Menubutton @menu.delete(index, last) self end + def xposition(index) + @menu.xposition(index) + end def yposition(index) @menu.yposition(index) end diff --git a/ext/tk/lib/tk/msgcat.rb b/ext/tk/lib/tk/msgcat.rb index 061e43fd8..162953f42 100644 --- a/ext/tk/lib/tk/msgcat.rb +++ b/ext/tk/lib/tk/msgcat.rb @@ -74,7 +74,11 @@ class TkMsgCatalog < TkObject "\n---< backtrace of Ruby side >-----\n" + _toUTF8(e.backtrace.join("\n")) + "\n---< backtrace of Tk side >-------" - msg.instance_variable_set(:@encoding, 'utf-8') + if TkCore::WITH_ENCODING + msg.force_encoding('utf-8') + else + msg.instance_variable_set(:@encoding, 'utf-8') + end rescue Exception msg = e.class.inspect + ': ' + e.message + "\n" + "\n---< backtrace of Ruby side >-----\n" + diff --git a/ext/tk/lib/tk/namespace.rb b/ext/tk/lib/tk/namespace.rb index 5bf6474c5..9d2213ff5 100644 --- a/ext/tk/lib/tk/namespace.rb +++ b/ext/tk/lib/tk/namespace.rb @@ -12,17 +12,24 @@ class TkNamespace < TkObject ].freeze Tk_Namespace_ID_TBL = TkCore::INTERP.create_table - Tk_Namespace_ID = ["ns".freeze, "00000".taint].freeze + + (Tk_Namespace_ID = ["ns".freeze, "00000".taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } Tk_NsCode_RetObjID_TBL = TkCore::INTERP.create_table TkCore::INTERP.init_ip_env{ - Tk_Namespace_ID_TBL.clear - Tk_NsCode_RetObjID_TBL.clear + Tk_Namespace_ID_TBL.mutex.synchronize{ Tk_Namespace_ID_TBL.clear } + Tk_NsCode_RetObjID_TBL.mutex.synchronize{ Tk_NsCode_RetObjID_TBL.clear } } def TkNamespace.id2obj(id) - Tk_Namespace_ID_TBL[id]? Tk_Namespace_ID_TBL[id]: id + Tk_Namespace_ID_TBL.mutex.synchronize{ + Tk_Namespace_ID_TBL[id]? Tk_Namespace_ID_TBL[id]: id + } end ##################################### @@ -65,11 +72,13 @@ class TkNamespace < TkObject def cget(slot) if slot == :namespace || slot == 'namespace' ns = super(slot) - if TkNamespace::Tk_Namespace_ID_TBL.key?(ns) - TkNamespace::Tk_Namespace_ID_TBL[ns] - else - ns - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + if TkNamespace::Tk_Namespace_ID_TBL.key?(ns) + TkNamespace::Tk_Namespace_ID_TBL[ns] + else + ns + end + } else super(slot) end @@ -79,9 +88,11 @@ class TkNamespace < TkObject if slot if slot == :namespace || slot == 'namespace' val = super(slot) - if TkNamespace::Tk_Namespace_ID_TBL.key?(val) - val = TkNamespace::Tk_Namespace_ID_TBL[val] - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + if TkNamespace::Tk_Namespace_ID_TBL.key?(val) + val = TkNamespace::Tk_Namespace_ID_TBL[val] + end + } else val = super(slot) end @@ -96,19 +107,23 @@ class TkNamespace < TkObject info = super() if TkComm::GET_CONFIGINFO_AS_ARRAY - info.map!{|inf| - if inf[0] == 'namespace' && - TkNamespace::Tk_Namespace_ID_TBL.key?(inf[-1]) - [inf[0], TkNamespace::Tk_Namespace_ID_TBL[inf[-1]]] - else - inf - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + info.map!{|inf| + if inf[0] == 'namespace' && + TkNamespace::Tk_Namespace_ID_TBL.key?(inf[-1]) + [inf[0], TkNamespace::Tk_Namespace_ID_TBL[inf[-1]]] + else + inf + end + } } else # ! TkComm::GET_CONFIGINFO_AS_ARRAY val = info['namespace'] - if TkNamespace::Tk_Namespace_ID_TBL.key?(val) - info['namespace'] = TkNamespace::Tk_Namespace_ID_TBL[val] - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + if TkNamespace::Tk_Namespace_ID_TBL.key?(val) + info['namespace'] = TkNamespace::Tk_Namespace_ID_TBL[val] + end + } end info @@ -215,9 +230,11 @@ class TkNamespace < TkObject def initialize(name = nil, parent = nil) unless name - # name = Tk_Namespace_ID.join('') - name = Tk_Namespace_ID.join(TkCore::INTERP._ip_id_) - Tk_Namespace_ID[1].succ! + Tk_Namespace_ID.mutex.synchronize{ + # name = Tk_Namespace_ID.join('') + name = Tk_Namespace_ID.join(TkCore::INTERP._ip_id_) + Tk_Namespace_ID[1].succ! + } end name = __tk_call('namespace', 'current') if name == '' if parent @@ -252,7 +269,9 @@ class TkNamespace < TkObject # create namespace __tk_call('namespace', 'eval', @fullname, '') - Tk_Namespace_ID_TBL[@fullname] = self + Tk_Namespace_ID_TBL.mutex.synchronize{ + Tk_Namespace_ID_TBL[@fullname] = self + } end def self.children(*args) @@ -260,11 +279,13 @@ class TkNamespace < TkObject # <pattern> must be glob-style pattern tk_split_simplelist(tk_call('namespace', 'children', *args)).collect{|ns| # ns is fullname - if Tk_Namespace_ID_TBL.key?(ns) - Tk_Namespace_ID_TBL[ns] - else - ns - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + if Tk_Namespace_ID_TBL.key?(ns) + Tk_Namespace_ID_TBL[ns] + else + ns + end + } } end def children(pattern=None) @@ -290,14 +311,24 @@ class TkNamespace < TkObject def code(script = Proc.new) if script.kind_of?(String) cmd = proc{|*args| - ret = ScopeArgs.new(@fullname,*args).instance_eval(script) + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + obj = ScopeArgs.new(@fullname,*args) + ret = obj.instance_exec(obj, script) + else + ret = ScopeArgs.new(@fullname,*args).instance_eval(script) + end id = ret.object_id TkNamespace::Tk_NsCode_RetObjID_TBL[id] = ret id } elsif script.kind_of?(Proc) cmd = proc{|*args| - ret = ScopeArgs.new(@fullname,*args).instance_eval(&script) + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + obj = ScopeArgs.new(@fullname,*args) + ret = obj.instance_exec(obj, &script) + else + ret = ScopeArgs.new(@fullname,*args).instance_eval(&script) + end id = ret.object_id TkNamespace::Tk_NsCode_RetObjID_TBL[id] = ret id @@ -319,11 +350,13 @@ class TkNamespace < TkObject def self.current ns = self.current_path - if Tk_Namespace_ID_TBL.key?(ns) - Tk_Namespace_ID_TBL[ns] - else - ns - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + if Tk_Namespace_ID_TBL.key?(ns) + Tk_Namespace_ID_TBL[ns] + else + ns + end + } end def current_namespace # ns_tk_call('namespace', 'current') @@ -335,11 +368,13 @@ class TkNamespace < TkObject def self.delete(*ns_list) tk_call('namespace', 'delete', *ns_list) ns_list.each{|ns| - if ns.kind_of?(TkNamespace) - Tk_Namespace_ID_TBL.delete(ns.path) - else - Tk_Namespace_ID_TBL.delete(ns.to_s) - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + if ns.kind_of?(TkNamespace) + Tk_Namespace_ID_TBL.delete(ns.path) + else + Tk_Namespace_ID_TBL.delete(ns.to_s) + end + } } end def delete @@ -371,7 +406,7 @@ class TkNamespace < TkObject def self.eval(namespace, cmd = Proc.new, *args) #tk_call('namespace', 'eval', namespace, cmd, *args) - TkNamespace.new(namespece).eval(cmd, *args) + TkNamespace.new(namespace).eval(cmd, *args) end =begin def eval(cmd = Proc.new, *args) @@ -444,11 +479,13 @@ class TkNamespace < TkObject def self.parent(namespace=None) ns = tk_call('namespace', 'parent', namespace) - if Tk_Namespace_ID_TBL.key?(ns) - Tk_Namespace_ID_TBL[ns] - else - ns - end + Tk_Namespace_ID_TBL.mutex.synchronize{ + if Tk_Namespace_ID_TBL.key?(ns) + Tk_Namespace_ID_TBL[ns] + else + ns + end + } end def parent tk_call('namespace', 'parent', @fullname) diff --git a/ext/tk/lib/tk/optiondb.rb b/ext/tk/lib/tk/optiondb.rb index 6a7708ac5..186811d37 100644 --- a/ext/tk/lib/tk/optiondb.rb +++ b/ext/tk/lib/tk/optiondb.rb @@ -8,7 +8,11 @@ module TkOptionDB extend Tk TkCommandNames = ['option'.freeze].freeze - CmdClassID = ['CMD_CLASS'.freeze, '00000'.taint].freeze + (CmdClassID = ['CMD_CLASS'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } module Priority WidgetDefault = 20 @@ -250,8 +254,10 @@ module TkOptionDB def __create_new_class(klass, func, safe = 4, add = false, parent = nil) if klass.kind_of?(TkWindow) carrier = klass.path - klass = CmdClassID.join(TkCore::INTERP._ip_id_) - CmdClassID[1].succ! + CmdClassID.mutex.synchronize{ + klass = CmdClassID.join(TkCore::INTERP._ip_id_) + CmdClassID[1].succ! + } parent = nil # ignore parent else klass = klass.to_s if klass.kind_of?(Symbol) @@ -312,7 +318,7 @@ module TkOptionDB :singleton_methods, :remove_const, :remove_method, :undef_method, :to_s, :inspect, :display, :method, :methods, :respond_to?, :instance_variable_get, :instance_variable_set, :instance_method, - :instance_eval, :instance_variables, :kind_of?, :is_a?, + :instance_eval, :instance_exec, :instance_variables, :kind_of?, :is_a?, :private_methods, :protected_methods, :public_methods ].each{|m| alias_method(m, :__null_method) } diff --git a/ext/tk/lib/tk/root.rb b/ext/tk/lib/tk/root.rb index 4d8328244..7237b4c61 100644 --- a/ext/tk/lib/tk/root.rb +++ b/ext/tk/lib/tk/root.rb @@ -41,7 +41,13 @@ class Tk::Root<TkWindow } end - root.instance_eval(&b) if block_given? + if block_given? + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + root.instance_exec(root, &b) + else + root.instance_eval(&b) + end + end root end diff --git a/ext/tk/lib/tk/scale.rb b/ext/tk/lib/tk/scale.rb index b97ed6807..bf2791ec5 100644 --- a/ext/tk/lib/tk/scale.rb +++ b/ext/tk/lib/tk/scale.rb @@ -14,9 +14,24 @@ class Tk::Scale<TkWindow cmd = keys.delete('command') keys['command'] = proc{|val| cmd.call(val.to_f)} end - #tk_call_without_enc('scale', @path, *hash_kv(keys, true)) - tk_call_without_enc(self.class::TkCommandNames[0], @path, - *hash_kv(keys, true)) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + #tk_call_without_enc('scale', @path, *hash_kv(keys, true)) + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + else + begin + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + rescue + tk_call_without_enc(self.class::TkCommandNames[0], @path) + keys = __check_available_configure_options(keys) + unless keys.empty? + tk_call_without_enc('destroy', @path) + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + end + end + end else #tk_call_without_enc('scale', @path) tk_call_without_enc(self.class::TkCommandNames[0], @path) diff --git a/ext/tk/lib/tk/scrollbar.rb b/ext/tk/lib/tk/scrollbar.rb index 66eadbd65..521fc7e40 100644 --- a/ext/tk/lib/tk/scrollbar.rb +++ b/ext/tk/lib/tk/scrollbar.rb @@ -19,9 +19,24 @@ class Tk::Scrollbar<TkWindow } if keys and keys != None - #tk_call_without_enc('scrollbar', @path, *hash_kv(keys, true)) - tk_call_without_enc(self.class::TkCommandNames[0], @path, - *hash_kv(keys, true)) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + #tk_call_without_enc('scrollbar', @path, *hash_kv(keys, true)) + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + else + begin + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + rescue + tk_call_without_enc(self.class::TkCommandNames[0], @path) + keys = __check_available_configure_options(keys) + unless keys.empty? + tk_call_without_enc('destroy', @path) + tk_call_without_enc(self.class::TkCommandNames[0], @path, + *hash_kv(keys, true)) + end + end + end else #tk_call_without_enc('scrollbar', @path) tk_call_without_enc(self.class::TkCommandNames[0], @path) @@ -103,6 +118,26 @@ class Tk::Scrollbar<TkWindow def activate(element=None) tk_send_without_enc('activate', element) end + + def moveto(fraction) + tk_send_without_enc('moveto', fraction) + self + end + + def scroll(*args) + tk_send_without_enc('scroll', *args) + self + end + + def scroll_units(num) + scroll(num, 'units') + self + end + + def scroll_pages(num) + scroll(num, 'pages') + self + end end #TkScrollbar = Tk::Scrollbar unless Object.const_defined? :TkScrollbar diff --git a/ext/tk/lib/tk/spinbox.rb b/ext/tk/lib/tk/spinbox.rb index e7f223aea..e372c5800 100644 --- a/ext/tk/lib/tk/spinbox.rb +++ b/ext/tk/lib/tk/spinbox.rb @@ -37,6 +37,22 @@ class Tk::Spinbox<Tk::Entry nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) diff --git a/ext/tk/lib/tk/text.rb b/ext/tk/lib/tk/text.rb index 2ed1d30cf..14b9be23f 100644 --- a/ext/tk/lib/tk/text.rb +++ b/ext/tk/lib/tk/text.rb @@ -250,7 +250,11 @@ class Tk::Text<TkTextWin def self.new(*args, &block) obj = super(*args){} obj.init_instance_variable - obj.instance_eval(&block) if defined? yield + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + obj.instance_exec(obj, &block) if defined? yield + else + obj.instance_eval(&block) if defined? yield + end obj end @@ -260,8 +264,12 @@ class Tk::Text<TkTextWin end def __destroy_hook__ - TkTextTag::TTagID_TBL.delete(@path) - TkTextMark::TMarkID_TBL.delete(@path) + TkTextTag::TTagID_TBL.mutex.synchronize{ + TkTextTag::TTagID_TBL.delete(@path) + } + TkTextTag::TMarkID_TBL.mutex.synchronize{ + TkTextMark::TMarkID_TBL.delete(@path) + } end def create_self(keys) @@ -712,15 +720,17 @@ class Tk::Text<TkTextWin def tag_delete(*tags) tk_send_without_enc('tag', 'delete', *(tags.collect{|tag| _get_eval_enc_str(tag)})) - if TkTextTag::TTagID_TBL[@path] - tags.each{|tag| - if tag.kind_of?(TkTextTag) - TkTextTag::TTagID_TBL[@path].delete(tag.id) - else - TkTextTag::TTagID_TBL[@path].delete(tag) - end - } - end + TkTextTag::TTagID_TBL.mutex.synchronize{ + if TkTextTag::TTagID_TBL[@path] + tags.each{|tag| + if tag.kind_of?(TkTextTag) + TkTextTag::TTagID_TBL[@path].delete(tag.id) + else + TkTextTag::TTagID_TBL[@path].delete(tag) + end + } + end + } self end alias deltag tag_delete diff --git a/ext/tk/lib/tk/textmark.rb b/ext/tk/lib/tk/textmark.rb index 6ce52b58d..72c1ce1ab 100644 --- a/ext/tk/lib/tk/textmark.rb +++ b/ext/tk/lib/tk/textmark.rb @@ -8,14 +8,26 @@ class TkTextMark<TkObject include Tk::Text::IndexModMethods TMarkID_TBL = TkCore::INTERP.create_table - Tk_TextMark_ID = ['mark'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TMarkID_TBL.clear } + (Tk_TextMark_ID = ['mark'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + TMarkID_TBL.mutex.synchronize{ TMarkID_TBL.clear } + } def TkTextMark.id2obj(text, id) tpath = text.path - return id unless TMarkID_TBL[tpath] - TMarkID_TBL[tpath][id]? TMarkID_TBL[tpath][id]: id + TMarkID_TBL.mutex.synchronize{ + if TMarkID_TBL[tpath] + TMarkID_TBL[tpath][id]? TMarkID_TBL[tpath][id]: id + else + id + end + } end def initialize(parent, index) @@ -24,12 +36,16 @@ class TkTextMark<TkObject #end @parent = @t = parent @tpath = parent.path - # @path = @id = Tk_TextMark_ID.join('') - @path = @id = Tk_TextMark_ID.join(TkCore::INTERP._ip_id_).freeze - TMarkID_TBL[@id] = self - TMarkID_TBL[@tpath] = {} unless TMarkID_TBL[@tpath] - TMarkID_TBL[@tpath][@id] = self - Tk_TextMark_ID[1].succ! + Tk_TextMark_ID.mutex.synchronize{ + # @path = @id = Tk_TextMark_ID.join('') + @path = @id = Tk_TextMark_ID.join(TkCore::INTERP._ip_id_).freeze + Tk_TextMark_ID[1].succ! + } + TMarkID_TBL.mutex.synchronize{ + TMarkID_TBL[@id] = self + TMarkID_TBL[@tpath] = {} unless TMarkID_TBL[@tpath] + TMarkID_TBL[@tpath][@id] = self + } tk_call_without_enc(@t.path, 'mark', 'set', @id, _get_eval_enc_str(index)) @t._addtag id, self @@ -124,27 +140,44 @@ end TktMark = TkTextMark class TkTextNamedMark<TkTextMark - def self.new(parent, name, *args) - if TMarkID_TBL[parent.path] && TMarkID_TBL[parent.path][name] - return TMarkID_TBL[parent.path][name] - else - super(parent, name, *args) - end + def self.new(parent, name, index=nil) + TMarkID_TBL.mutex.synchronize{ + if TMarkID_TBL[parent.path] && TMarkID_TBL[parent.path][name] + obj = TMarkID_TBL[parent.path][name] + else + # super(parent, name, *args) + (obj = self.allocate).instance_eval{ + @parent = @t = parent + @tpath = parent.path + @path = @id = name + TMarkID_TBL[@id] = self + TMarkID_TBL[@tpath] = {} unless TMarkID_TBL[@tpath] + TMarkID_TBL[@tpath][@id] = self unless TMarkID_TBL[@tpath][@id] + @t._addtag @id, self + } + obj + end + + if obj && index + tk_call_without_enc(parent.path, 'mark', 'set', name, + _get_eval_enc_str(index)) + end + obj + } end def initialize(parent, name, index=nil) + # dummy:: not called by 'new' method + #unless parent.kind_of?(Tk::Text) # fail ArgumentError, "expect Tk::Text for 1st argument" #end @parent = @t = parent @tpath = parent.path @path = @id = name - TMarkID_TBL[@id] = self - TMarkID_TBL[@tpath] = {} unless TMarkID_TBL[@tpath] - TMarkID_TBL[@tpath][@id] = self unless TMarkID_TBL[@tpath][@id] tk_call_without_enc(@t.path, 'mark', 'set', @id, _get_eval_enc_str(index)) if index - @t._addtag id, self + @t._addtag @id, self end end TktNamedMark = TkTextNamedMark diff --git a/ext/tk/lib/tk/texttag.rb b/ext/tk/lib/tk/texttag.rb index 8264d5293..792d544fe 100644 --- a/ext/tk/lib/tk/texttag.rb +++ b/ext/tk/lib/tk/texttag.rb @@ -10,14 +10,26 @@ class TkTextTag<TkObject include Tk::Text::IndexModMethods TTagID_TBL = TkCore::INTERP.create_table - Tk_TextTag_ID = ['tag'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TTagID_TBL.clear } + (Tk_TextTag_ID = ['tag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + TTagID_TBL.mutex.synchronize{ TTagID_TBL.clear } + } def TkTextTag.id2obj(text, id) tpath = text.path - return id unless TTagID_TBL[tpath] - TTagID_TBL[tpath][id]? TTagID_TBL[tpath][id]: id + TTagID_TBL.mutex.synchronize{ + if TTagID_TBL[tpath] + TTagID_TBL[tpath][id]? TTagID_TBL[tpath][id]: id + else + id + end + } end def initialize(parent, *args) @@ -26,12 +38,16 @@ class TkTextTag<TkObject #end @parent = @t = parent @tpath = parent.path - # @path = @id = Tk_TextTag_ID.join('') - @path = @id = Tk_TextTag_ID.join(TkCore::INTERP._ip_id_).freeze - # TTagID_TBL[@id] = self - TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath] - TTagID_TBL[@tpath][@id] = self - Tk_TextTag_ID[1].succ! + Tk_TextTag_ID.mutex.synchronize{ + # @path = @id = Tk_TextTag_ID.join('') + @path = @id = Tk_TextTag_ID.join(TkCore::INTERP._ip_id_).freeze + Tk_TextTag_ID[1].succ! + } + TTagID_TBL.mutex.synchronize{ + TTagID_TBL[@id] = self + TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath] + TTagID_TBL[@tpath][@id] = self + } #tk_call @t.path, "tag", "configure", @id, *hash_kv(keys) if args != [] keys = args.pop @@ -221,7 +237,9 @@ class TkTextTag<TkObject def destroy tk_call_without_enc(@t.path, 'tag', 'delete', @id) - TTagID_TBL[@tpath].delete(@id) if TTagID_TBL[@tpath] + TTagID_TBL.mutex.synchronize{ + TTagID_TBL[@tpath].delete(@id) if TTagID_TBL[@tpath] + } self end end @@ -229,33 +247,48 @@ TktTag = TkTextTag class TkTextNamedTag<TkTextTag def self.new(parent, name, *args) - if TTagID_TBL[parent.path] && TTagID_TBL[parent.path][name] - tagobj = TTagID_TBL[parent.path][name] - if args != [] - keys = args.pop - if keys.kind_of?(Hash) - tagobj.add(*args) if args != [] - tagobj.configure(keys) - else - args.push keys - tagobj.add(*args) - end + tagobj = nil + TTagID_TBL.mutex.synchronize{ + if TTagID_TBL[parent.path] && TTagID_TBL[parent.path][name] + tagobj = TTagID_TBL[parent.path][name] + else + # super(parent, name, *args) + (tagobj = self.allocate).instance_eval{ + @parent = @t = parent + @tpath = parent.path + @path = @id = name + TTagID_TBL[@id] = self + TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath] + TTagID_TBL[@tpath][@id] = self unless TTagID_TBL[@tpath][@id] + @t._addtag @id, self + } + end + } + + if args != [] + keys = args.pop + if keys.kind_of?(Hash) + tagobj.add(*args) if args != [] + tagobj.configure(keys) + else + args.push keys + tagobj.add(*args) end - return tagobj - else - super(parent, name, *args) end + + tagobj end def initialize(parent, name, *args) + # dummy:: not called by 'new' method + #unless parent.kind_of?(Tk::Text) # fail ArgumentError, "expect Tk::Text for 1st argument" #end @parent = @t = parent @tpath = parent.path @path = @id = name - TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath] - TTagID_TBL[@tpath][@id] = self unless TTagID_TBL[@tpath][@id] + #if mode # tk_call @t.path, "addtag", @id, *args #end @@ -269,7 +302,7 @@ class TkTextNamedTag<TkTextTag add(*args) end end - @t._addtag id, self + @t._addtag @id, self end end TktNamedTag = TkTextNamedTag diff --git a/ext/tk/lib/tk/timer.rb b/ext/tk/lib/tk/timer.rb index 47f2b7935..3588f0c48 100644 --- a/ext/tk/lib/tk/timer.rb +++ b/ext/tk/lib/tk/timer.rb @@ -11,7 +11,12 @@ class TkTimer TkCommandNames = ['after'.freeze].freeze - Tk_CBID = ['a'.freeze, '00000'.taint].freeze + (Tk_CBID = ['a'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + Tk_CBTBL = {}.taint TkCore::INTERP.add_tk_procs('rb_after', 'id', <<-'EOL') @@ -96,9 +101,9 @@ class TkTimer return self end @after_script = "rb_after #{@id}" - @after_id = tk_call_without_enc('after', sleep, @after_script) @current_args = args @current_script = [sleep, @after_script] + @after_id = tk_call_without_enc('after', sleep, @after_script) self end @@ -138,9 +143,11 @@ class TkTimer end def initialize(*args, &b) - # @id = Tk_CBID.join('') - @id = Tk_CBID.join(TkCore::INTERP._ip_id_) - Tk_CBID[1].succ! + Tk_CBID.mutex.synchronize{ + # @id = Tk_CBID.join('') + @id = Tk_CBID.join(TkCore::INTERP._ip_id_) + Tk_CBID[1].succ! + } @wait_var = TkVariable.new(0) diff --git a/ext/tk/lib/tk/ttk_selector.rb b/ext/tk/lib/tk/ttk_selector.rb index f89b5c76b..72ed637a3 100644 --- a/ext/tk/lib/tk/ttk_selector.rb +++ b/ext/tk/lib/tk/ttk_selector.rb @@ -56,6 +56,15 @@ module Tk @TOPLEVEL_ALIAS_TABLE[:Tile] = @TOPLEVEL_ALIAS_TABLE[:Ttk] ################################################ + # register some Ttk widgets as default + # (Ttk is a standard library on Tcl/Tk8.5+) + @TOPLEVEL_ALIAS_TABLE[:Ttk].each{|sym, file| + unless Object.autoload?(sym) || Object.const_defined?(sym) + Object.autoload(sym, file) + end + } + + ################################################ @TOPLEVEL_ALIAS_SETUP_PROC[:Tile] = @TOPLEVEL_ALIAS_SETUP_PROC[:Ttk] = proc{|mod| diff --git a/ext/tk/lib/tk/validation.rb b/ext/tk/lib/tk/validation.rb index 0c5b5c61b..1da38c776 100644 --- a/ext/tk/lib/tk/validation.rb +++ b/ext/tk/lib/tk/validation.rb @@ -249,6 +249,22 @@ class TkValidateCommand nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); # diff --git a/ext/tk/lib/tk/variable.rb b/ext/tk/lib/tk/variable.rb index 632f00ced..f738a96ee 100644 --- a/ext/tk/lib/tk/variable.rb +++ b/ext/tk/lib/tk/variable.rb @@ -16,7 +16,18 @@ class TkVariable #TkVar_ID_TBL = {} TkVar_CB_TBL = TkCore::INTERP.create_table TkVar_ID_TBL = TkCore::INTERP.create_table - Tk_VARIABLE_ID = ["v".freeze, "00000".taint].freeze + (Tk_VARIABLE_ID = ["v".freeze, "00000".taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + TkCore::INTERP.init_ip_env{ + TkVar_CB_TBL.mutex.synchronize{ TkVar_CB_TBL.clear } + TkVar_ID_TBL.mutex.synchronize{ TkVar_ID_TBL.clear } + } + + major, minor, type, type_name, patchlevel = TclTkLib.get_version + USE_OLD_TRACE_OPTION_STYLE = (major < 8) || (major == 8 && minor < 4) #TkCore::INTERP.add_tk_procs('rb_var', 'args', # "ruby [format \"TkVariable.callback %%Q!%s!\" $args]") @@ -44,10 +55,10 @@ class TkVariable def TkVariable.callback(id, name1, name2, op) #name1,name2,op = tk_split_list(args) #name1,name2,op = tk_split_simplelist(args) - if TkVar_CB_TBL[id] + if cb_obj = TkVar_CB_TBL[id] #_get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op)) begin - _get_eval_string(TkVar_CB_TBL[id].trace_callback(name2, op)) + _get_eval_string(cb_obj.trace_callback(name2, op)) rescue SystemExit exit(0) rescue Interrupt @@ -59,7 +70,11 @@ class TkVariable "\n---< backtrace of Ruby side >-----\n" + _toUTF8(e.backtrace.join("\n")) + "\n---< backtrace of Tk side >-------" - msg.instance_variable_set(:@encoding, 'utf-8') + if TkCore::WITH_ENCODING + msg.force_encoding('utf-8') + else + msg.instance_variable_set(:@encoding, 'utf-8') + end rescue Exception msg = e.class.inspect + ': ' + e.message + "\n" + "\n---< backtrace of Ruby side >-----\n" + @@ -267,11 +282,15 @@ class TkVariable def initialize(val="", type=nil) # @id = Tk_VARIABLE_ID.join('') begin - @id = Tk_VARIABLE_ID.join(TkCore::INTERP._ip_id_) - Tk_VARIABLE_ID[1].succ! + Tk_VARIABLE_ID.mutex.synchronize{ + @id = Tk_VARIABLE_ID.join(TkCore::INTERP._ip_id_) + Tk_VARIABLE_ID[1].succ! + } end until INTERP._invoke_without_enc('info', 'globals', @id).empty? - TkVar_ID_TBL[@id] = self + TkVar_ID_TBL.mutex.synchronize{ + TkVar_ID_TBL[@id] = self + } @var = @id @elem = nil @@ -1263,56 +1282,101 @@ end end end + def _check_trace_opt(opts) + if opts.kind_of?(Array) + opt_str = opts.map{|s| s.to_s}.join(' ') + else + opt_str = opts.to_s + end + + fail ArgumentError, 'null trace option' if opt_str.empty? + + if opt_str =~ /[^arwu\s]/ + # new format (Tcl/Tk8.4+?) + if opts.kind_of?(Array) + opt_ary = opts.map{|opt| opt.to_s.strip} + else + opt_ary = opt_str.split(/\s+|\|/) + opt_ary.delete('') + end + if USE_OLD_TRACE_OPTION_STYLE + opt_ary.uniq.map{|opt| + case opt + when 'array' + 'a' + when 'read' + 'r' + when 'write' + 'w' + when 'unset' + 'u' + else + fail ArgumentError, "unsupported trace option '#{opt}' on Tcl/Tk#{Tk::TCL_PATCHLEVEL}" + end + }.join + else + opt_ary + end + else + # old format + opt_ary = opt_str.delete('^arwu').split(//).uniq + if USE_OLD_TRACE_OPTION_STYLE + opt_ary.join + else + opt_ary.map{|c| + case c + when 'a' + 'array' + when 'r' + 'read' + when 'w' + 'write' + when 'u' + 'unset' + end + } + end + end + end + private :_check_trace_opt + def trace(opts, cmd = Proc.new) - @trace_var = [] if @trace_var == nil - #opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') - opts = opts.to_s - opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') - @trace_var.unshift([opts,cmd]) + opts = _check_trace_opt(opts) + (@trace_var ||= []).unshift([opts,cmd]) + if @trace_opts == nil TkVar_CB_TBL[@id] = self - @trace_opts = opts.dup - Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 - Tk.tk_call_without_enc('trace', 'add', 'variable', - @id, @trace_opts, 'rb_var') + @trace_opts = opts + if USE_OLD_TRACE_OPTION_STYLE + Tk.tk_call_without_enc('trace', 'variable', + @id, @trace_opts, 'rb_var ' << @id) else - # TCL_VERSION <= 8.3 - Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var') + Tk.tk_call_without_enc('trace', 'add', 'variable', + @id, @trace_opts, 'rb_var ' << @id) end -=end else newopts = @trace_opts.dup - #opts.each_byte{|c| newopts += c.chr unless newopts.index(c)} - opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)} - if newopts != @trace_opts - Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, - 'rb_var ' << @id) - @trace_opts.replace(newopts) - Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 - Tk.tk_call_without_enc('trace', 'remove', 'variable', - @id, @trace_opts, 'rb_var') - @trace_opts.replace(newopts) - Tk.tk_call_without_enc('trace', 'add', 'variable', - @id, @trace_opts, 'rb_var') - else - # TCL_VERSION <= 8.3 + if USE_OLD_TRACE_OPTION_STYLE + opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} + if newopts != @trace_opts Tk.tk_call_without_enc('trace', 'vdelete', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) @trace_opts.replace(newopts) Tk.tk_call_without_enc('trace', 'variable', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) + end + else + newopts |= opts + unless (newopts - @trace_opts).empty? + Tk.tk_call_without_enc('trace', 'remove', 'variable', + @id, @trace_opts, 'rb_var ' << @id) + @trace_opts.replace(newopts) + Tk.tk_call_without_enc('trace', 'add', 'variable', + @id, @trace_opts, 'rb_var ' << @id) end -=end end end + self end @@ -1321,65 +1385,54 @@ end fail(RuntimeError, "invalid for a TkVariable which denotes an element of Tcl's array") end - @trace_elem = {} if @trace_elem == nil - @trace_elem[elem] = [] if @trace_elem[elem] == nil - opts = opts.to_s - opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') - @trace_elem[elem].unshift([opts,cmd]) + + opts = _check_trace_opt(opts) + + ((@trace_elem ||= {})[elem] ||= []).unshift([opts,cmd]) + if @trace_opts == nil TkVar_CB_TBL[@id] = self - @trace_opts = opts.dup - Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 + @trace_opts = opts + if USE_OLD_TRACE_OPTION_STYLE Tk.tk_call_without_enc('trace', 'add', 'variable', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) else - # TCL_VERSION <= 8.3 Tk.tk_call_without_enc('trace', 'variable', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) end -=end else newopts = @trace_opts.dup - # opts.each_byte{|c| newopts += c.chr unless newopts.index(c)} - opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)} - if newopts != @trace_opts - Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, - 'rb_var ' << @id) - @trace_opts.replace(newopts) - Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 - Tk.tk_call_without_enc('trace', 'remove', 'variable', - @id, @trace_opts, 'rb_var') - @trace_opts.replace(newopts) - Tk.tk_call_without_enc('trace', 'add', 'variable', - @id, @trace_opts, 'rb_var') - else - # TCL_VERSION <= 8.3 + if USE_OLD_TRACE_OPTION_STYLE + opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} + if newopts != @trace_opts Tk.tk_call_without_enc('trace', 'vdelete', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) @trace_opts.replace(newopts) Tk.tk_call_without_enc('trace', 'variable', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) + end + else + newopts |= opts + unless (newopts - @trace_opts).empty? + Tk.tk_call_without_enc('trace', 'remove', 'variable', + @id, @trace_opts, 'rb_var ' << @id) + @trace_opts.replace(newopts) + Tk.tk_call_without_enc('trace', 'add', 'variable', + @id, @trace_opts, 'rb_var ' << @id) end -=end end end + self end - def trace_vinfo + def trace_info return [] unless @trace_var @trace_var.dup end + alias trace_vinfo trace_info - def _trace_vinfo_for_element(elem) + def trace_info_for_element(elem) if @elem fail(RuntimeError, "invalid for a TkVariable which denotes an element of Tcl's array") @@ -1388,141 +1441,180 @@ end return [] unless @trace_elem[elem] @trace_elem[elem].dup end + alias trace_vinfo_for_element trace_info_for_element - def trace_vdelete(opts,cmd) + def trace_remove(opts,cmd) return self unless @trace_var.kind_of? Array - opts = opts.to_s - opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') + + opts = _check_trace_opt(opts) + idx = -1 - newopts = '' - @trace_var.each_with_index{|e,i| - 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)} - e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)} - } + if USE_OLD_TRACE_OPTION_STYLE + newopts = '' + @trace_var.each_with_index{|e, i| + if idx < 0 && e[1] == cmd + diff = false + ['a', 'r', 'w', 'u'].each{|c| + break if (diff = e[0].index(c) ^ opts.index(c)) + } + unless diff + #find + idx = i + next + end + end + e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} + } + else + newopts = [] + @trace_var.each_with_index{|e, i| + if idx < 0 && e[1] == cmd && + e[0].size == opts.size && (e[0] - opts).empty? + # find + idx = i + next + end + newopts |= e[0] + } + end + if idx >= 0 @trace_var.delete_at(idx) else return self end - @trace_elem.each{|elem| + (@trace_elem ||= {}).each{|elem| @trace_elem[elem].each{|e| - # e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} - e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)} + if USE_OLD_TRACE_OPTION_STYLE + e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} + else + newopts |= e[0] + end } } - newopts = newopts.to_s - newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('') - if newopts != @trace_opts - Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 - Tk.tk_call_without_enc('trace', 'remove', 'variable', - @id, @trace_opts, 'rb_var') - else - # TCL_VERSION <= 8.3 + if USE_OLD_TRACE_OPTION_STYLE + diff = false + @trace_opts.each_byte{|c| break if (diff = ! newopts.index(c))} + if diff Tk.tk_call_without_enc('trace', 'vdelete', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) + @trace_opts.replace(newopts) + unless @trace_opts.empty? + Tk.tk_call_without_enc('trace', 'variable', + @id, @trace_opts, 'rb_var ' << @id) + end end -=end - @trace_opts.replace(newopts) - if @trace_opts != '' - Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 + else + unless (@trace_opts - newopts).empty? + Tk.tk_call_without_enc('trace', 'remove', 'variable', + @id, @trace_opts, 'rb_var ' << @id) + @trace_opts.replace(newopts) + unless @trace_opts.empty? Tk.tk_call_without_enc('trace', 'add', 'variable', - @id, @trace_opts, 'rb_var') - else - # TCL_VERSION <= 8.3 - Tk.tk_call_without_enc('trace', 'variable', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) end -=end end end self end + alias trace_delete trace_remove + alias trace_vdelete trace_remove - def trace_vdelete_for_element(elem,opts,cmd) + def trace_remove_for_element(elem,opts,cmd) if @elem fail(RuntimeError, "invalid for a TkVariable which denotes an element of Tcl's array") end return self unless @trace_elem.kind_of? Hash return self unless @trace_elem[elem].kind_of? Array - opts = opts.to_s - opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') + + opts = _check_trace_opt(opts) + idx = -1 - @trace_elem[elem].each_with_index{|e,i| - if idx < 0 && e[0] == opts && e[1] == cmd - idx = i - next - end - } + if USE_OLD_TRACE_OPTION_STYLE + @trace_elem[elem].each_with_index{|e, i| + if idx < 0 && e[1] == cmd + diff = false + ['a', 'r', 'w', 'u'].each{|c| + break if (diff = e[0].index(c) ^ opts.index(c)) + } + unless diff + #find + idx = i + next + end + end + } + else + @trace_elem[elem].each_with_index{|e, i| + if idx < 0 && e[1] == cmd && + e[0].size == opts.size && (e[0] - opts).empty? + # find + idx = i + next + end + } + end + if idx >= 0 @trace_elem[elem].delete_at(idx) else return self end - newopts = '' - @trace_var.each{|e| - # e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} - e[0].each_byte{|c| newopts.concat(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)} - e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)} + if USE_OLD_TRACE_OPTION_STYLE + newopts = '' + @trace_var.each{|e| + e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} } - } + @trace_elem.each{|elem| + @trace_elem[elem].each{|e| + e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} + } + } + else + newopts = [] + @trace_var.each{|e| + newopts |= e[0] + } + @trace_elem.each{|elem| + @trace_elem[elem].each{|e| + e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} + } + } + end - newopts = newopts.to_s - newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('') - if newopts != @trace_opts - Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 - Tk.tk_call_without_enc('trace', 'remove', 'variable', - @id, @trace_opts, 'rb_var') - else - # TCL_VERSION <= 8.3 + if USE_OLD_TRACE_OPTION_STYLE + diff = false + @trace_opts.each_byte{|c| break if (diff = ! newopts.index(c))} + if diff Tk.tk_call_without_enc('trace', 'vdelete', - @id, @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) + @trace_opts.replace(newopts) + unless @trace_opts.empty? + Tk.tk_call_without_enc('trace', 'variable', + @id, @trace_opts, 'rb_var ' << @id) + end end -=end - @trace_opts.replace(newopts) - if @trace_opts != '' - Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, - 'rb_var ' << @id) -=begin - if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION - # TCL_VERSION >= 8.4 + else + unless (@trace_opts - newopts).empty? + Tk.tk_call_without_enc('trace', 'remove', 'variable', + @id, @trace_opts, 'rb_var ' << @id) + @trace_opts.replace(newopts) + unless @trace_opts.empty? Tk.tk_call_without_enc('trace', 'add', 'variable', - @id, @trace_opts, 'rb_var') - else - # TCL_VERSION <= 8.3 - Tk.tk_call_without_enc('trace', 'variable', @id, - @trace_opts, 'rb_var') + @id, @trace_opts, 'rb_var ' << @id) end -=end end end self end + alias trace_delete_for_element trace_remove_for_element + alias trace_vdelete_for_element trace_remove_for_element end class TkVarAccess<TkVariable @@ -1532,12 +1624,23 @@ class TkVarAccess<TkVariable return name end - if v = TkVar_ID_TBL[name] - v.value = args[0] unless args.empty? - return v - end + name = name.to_s + v = nil + TkVar_ID_TBL.mutex.synchronize{ + if v = TkVar_ID_TBL[name] + v.value = args[0] unless args.empty? + return v + else + (v = self.allocate).instance_eval{ + @id = name + TkVar_ID_TBL[@id] = self + @var = @id + } + end + } - super(name, *args) + v.instance_eval{ initialize(name, *args) } + v end def self.new_hash(name, *args) @@ -1549,27 +1652,38 @@ class TkVarAccess<TkVariable return name end - if v = TkVar_ID_TBL[name] - unless v.is_hash? - fail ArgumentError, "already exist as a scalar variable" + name = name.to_s + v = nil + TkVar_ID_TBL.mutex.synchronize{ + if v = TkVar_ID_TBL[name] + unless v.is_hash? + fail ArgumentError, "already exist as a scalar variable" + end + v.value = args[0] unless args.empty? + return v + else + (v = self.allocate).instance_eval{ + @id = name + TkVar_ID_TBL[@id] = self + @var = @id + } end - v.value = args[0] unless args.empty? - return v - end + } INTERP._invoke_without_enc('global', name) if args.empty? && INTERP._invoke_without_enc('array', 'exist', name) == '0' - self.new(name, {}) # force creating + v.instance_eval{ initialize(name, {}) } # force creating else - self.new(name, *args) + v.instance_eval{ initialize(name, *args) } end + v end def initialize(varname, val=nil) - @id = varname - TkVar_ID_TBL[@id] = self + # @id = varname + # TkVar_ID_TBL[@id] = self - @var = @id + # @var = @id @elem = nil @def_default = false diff --git a/ext/tk/lib/tk/virtevent.rb b/ext/tk/lib/tk/virtevent.rb index d47e80aec..ae31ac1f8 100644 --- a/ext/tk/lib/tk/virtevent.rb +++ b/ext/tk/lib/tk/virtevent.rb @@ -9,10 +9,17 @@ class TkVirtualEvent<TkObject TkCommandNames = ['event'.freeze].freeze - TkVirtualEventID = ["VirtEvent".freeze, "00000".taint].freeze + (TkVirtualEventID = ["VirtEvent".freeze, "00000".taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + TkVirtualEventTBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ TkVirtualEventTBL.clear } + TkCore::INTERP.init_ip_env{ + TkVirtualEventTBL.mutex.synchronize{ TkVirtualEventTBL.clear } + } class PreDefVirtEvent<self def self.new(event, *sequences) @@ -21,22 +28,30 @@ class TkVirtualEvent<TkObject elsif event !~ /^<.*>$/ event = '<' + event + '>' end - if TkVirtualEvent::TkVirtualEventTBL.has_key?(event) - TkVirtualEvent::TkVirtualEventTBL[event] - else - super(event, *sequences) - end + TkVirtualEvent::TkVirtualEventTBL.mutex.synchronize{ + if TkVirtualEvent::TkVirtualEventTBL.has_key?(event) + TkVirtualEvent::TkVirtualEventTBL[event] + else + # super(event, *sequences) + (obj = self.allocate).instance_eval{ + initialize(event, *sequences) + TkVirtualEvent::TkVirtualEventTBL[@id] = self + } + end + } end def initialize(event, *sequences) @path = @id = event - TkVirtualEvent::TkVirtualEventTBL[@id] = self - add(*sequences) + _add_sequences(sequences) end end def TkVirtualEvent.getobj(event) - obj = TkVirtualEventTBL[event] + obj = nil + TkVirtualEventTBL.mutex.synchronize{ + obj = TkVirtualEventTBL[event] + } if obj obj else @@ -55,19 +70,31 @@ class TkVirtualEvent<TkObject end def initialize(*sequences) - # @path = @id = '<' + TkVirtualEventID.join('') + '>' - @path = @id = '<' + TkVirtualEventID.join(TkCore::INTERP._ip_id_) + '>' - TkVirtualEventID[1].succ! - add(*sequences) + TkVirtualEventID.mutex.synchronize{ + # @path = @id = '<' + TkVirtualEventID.join('') + '>' + @path = @id = '<' + TkVirtualEventID.join(TkCore::INTERP._ip_id_) + '>' + TkVirtualEventID[1].succ! + } + _add_sequences(sequences) end - def add(*sequences) - if sequences != [] + def _add_sequences(seq_ary) + unless seq_ary.empty? tk_call_without_enc('event', 'add', "<#{@id}>", - *(sequences.collect{|seq| + *(seq_ary.collect{|seq| "<#{tk_event_sequence(seq)}>" }) ) - TkVirtualEventTBL[@id] = self + end + self + end + private :_add_sequences + + def add(*sequences) + if sequences != [] + _add_sequences(sequences) + TkVirtualEventTBL.mutex.synchronize{ + TkVirtualEventTBL[@id] = self + } end self end @@ -75,20 +102,26 @@ class TkVirtualEvent<TkObject def delete(*sequences) if sequences == [] tk_call_without_enc('event', 'delete', "<#{@id}>") - TkVirtualEventTBL.delete(@id) + TkVirtualEventTBL.mutex.synchronize{ + TkVirtualEventTBL.delete(@id) + } else tk_call_without_enc('event', 'delete', "<#{@id}>", *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>" }) ) - TkVirtualEventTBL.delete(@id) if info == [] + if tk_call_without_enc('event','info',"<#{@id}>").empty? + TkVirtualEventTBL.mutex.synchronize{ + TkVirtualEventTBL.delete(@id) + } + end end self end def info tk_call_without_enc('event','info',"<#{@id}>").split(/\s+/).collect!{|seq| - l = seq.scan(/<*[^<>]+>*/).collect!{|subseq| + lst = seq.scan(/<*[^<>]+>*/).collect!{|subseq| case (subseq) when /^<<[^<>]+>>$/ TkVirtualEvent.getobj(subseq[1..-2]) @@ -98,7 +131,7 @@ class TkVirtualEvent<TkObject subseq.split('') end }.flatten - (l.size == 1) ? l[0] : l + (lst.size == 1) ? lst[0] : lst } end end diff --git a/ext/tk/lib/tk/wm.rb b/ext/tk/lib/tk/wm.rb index 1f432a384..49dd4d73c 100644 --- a/ext/tk/lib/tk/wm.rb +++ b/ext/tk/lib/tk/wm.rb @@ -5,273 +5,407 @@ require 'tk' module Tk module Wm - include TkComm + #include TkComm + extend TkCore TkCommandNames = ['wm'.freeze].freeze TOPLEVEL_METHODCALL_OPTKEYS = {} - def aspect(*args) + def Wm.aspect(win, *args) if args.length == 0 - list(tk_call_without_enc('wm', 'aspect', path)) + list(tk_call_without_enc('wm', 'aspect', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call('wm', 'aspect', path, *args) - self + tk_call('wm', 'aspect', win.epath, *args) + win end end + def aspect(*args) + Wm.aspect(self, *args) + end + alias wm_aspect aspect TOPLEVEL_METHODCALL_OPTKEYS['aspect'] = 'aspect' - def attributes(slot=nil,value=None) + def Wm.attributes(win, slot=nil,value=TkComm::None) if slot == nil - lst = tk_split_list(tk_call('wm', 'attributes', path)) + lst = tk_split_list(tk_call('wm', 'attributes', win.epath)) info = {} while key = lst.shift info[key[1..-1]] = lst.shift end info elsif slot.kind_of? Hash - tk_call('wm', 'attributes', path, *hash_kv(slot)) - self - elsif value == None - tk_call('wm', 'attributes', path, "-#{slot}") + tk_call('wm', 'attributes', win.epath, *hash_kv(slot)) + win + elsif value == TkComm::None + tk_call('wm', 'attributes', win.epath, "-#{slot}") else - tk_call('wm', 'attributes', path, "-#{slot}", value) - self + tk_call('wm', 'attributes', win.epath, "-#{slot}", value) + win end end + def attributes(slot=nil,value=TkComm::None) + Wm.attributes(self, slot, value) + end + alias wm_attributes attributes TOPLEVEL_METHODCALL_OPTKEYS['attributes'] = 'attributes' - def client(name=None) - if name == None - tk_call('wm', 'client', path) + def Wm.client(win, name=TkComm::None) + if name == TkComm::None + tk_call('wm', 'client', win.epath) else name = '' if name == nil - tk_call('wm', 'client', path, name) - self + tk_call('wm', 'client', win.epath, name) + win end end + def client(name=TkComm::None) + Wm.client(self, name) + end + alias wm_client client TOPLEVEL_METHODCALL_OPTKEYS['client'] = 'client' - def colormapwindows(*args) + def Wm.colormapwindows(win, *args) if args.size == 0 - list(tk_call_without_enc('wm', 'colormapwindows', path)) + list(tk_call_without_enc('wm', 'colormapwindows', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call_without_enc('wm', 'colormapwindows', path, *args) - self + tk_call_without_enc('wm', 'colormapwindows', win.epath, *args) + win end end + def colormapwindows(*args) + Wm.colormapwindows(self, *args) + end + alias wm_colormapwindows colormapwindows TOPLEVEL_METHODCALL_OPTKEYS['colormapwindows'] = 'colormapwindows' - def wm_command(value=nil) + def Wm.command(win, value=nil) if value - tk_call('wm', 'command', path, value) - self + tk_call('wm', 'command', epath, value) + win else - #procedure(tk_call('wm', 'command', path)) - tk_call('wm', 'command', path) + #procedure(tk_call('wm', 'command', epath)) + tk_call('wm', 'command', epath) end end + def wm_command(value=nil) + Wm.command(self, value) + end TOPLEVEL_METHODCALL_OPTKEYS['wm_command'] = 'wm_command' - def deiconify(ex = true) + def Wm.deiconify(win, ex = true) if ex - tk_call_without_enc('wm', 'deiconify', path) + tk_call_without_enc('wm', 'deiconify', win.epath) else - self.iconify + Wm.iconify(win) end - self + win end + def deiconify(ex = true) + Wm.deiconify(self, ex) + end + alias wm_deiconify deiconify - def focusmodel(mode = nil) + def Wm.focusmodel(win, mode = nil) if mode - tk_call_without_enc('wm', 'focusmodel', path, mode) - self + tk_call_without_enc('wm', 'focusmodel', win.epath, mode) + win else - tk_call_without_enc('wm', 'focusmodel', path) + tk_call_without_enc('wm', 'focusmodel', win.epath) end end + def focusmodel(mode = nil) + Wm.focusmodel(self, mode) + end + alias wm_focusmodel focusmodel TOPLEVEL_METHODCALL_OPTKEYS['focusmodel'] = 'focusmodel' + def Wm.forget(win) + # Tcl/Tk 8.5+ + # work with dockable frames + tk_call_without_enc('wm', 'forget', win.epath) + win + end + def wm_forget + Wm.forget(self) + end + + def Wm.frame(win) + tk_call_without_enc('wm', 'frame', win.epath) + end def frame - tk_call_without_enc('wm', 'frame', path) + Wm.frame(self) end + alias wm_frame frame - def geometry(geom=nil) + def Wm.geometry(win, geom=nil) if geom - tk_call_without_enc('wm', 'geometry', path, geom) - self + tk_call_without_enc('wm', 'geometry', win.epath, geom) + win else - tk_call_without_enc('wm', 'geometry', path) + tk_call_without_enc('wm', 'geometry', win.epath) end end + def geometry(geom=nil) + Wm.geometry(self, geom) + end + alias wm_geometry geometry TOPLEVEL_METHODCALL_OPTKEYS['geometry'] = 'geometry' - def wm_grid(*args) + def Wm.grid(win, *args) if args.size == 0 - list(tk_call_without_enc('wm', 'grid', path)) + list(tk_call_without_enc('wm', 'grid', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call_without_enc('wm', 'grid', path, *args) - self + tk_call_without_enc('wm', 'grid', win.epath, *args) + win end end + def wm_grid(*args) + Wm.grid(self, *args) + end TOPLEVEL_METHODCALL_OPTKEYS['wm_grid'] = 'wm_grid' - def group(leader = nil) + def Wm.group(win, leader = nil) if leader - tk_call('wm', 'group', path, leader) - self + tk_call('wm', 'group', win.epath, leader) + win else - window(tk_call('wm', 'group', path)) + window(tk_call('wm', 'group', win.epath)) end end + def group(leader = nil) + Wm.group(self, leader) + end + alias wm_group group TOPLEVEL_METHODCALL_OPTKEYS['group'] = 'group' - def iconbitmap(bmp=nil) + def Wm.iconbitmap(win, bmp=nil) if bmp - tk_call_without_enc('wm', 'iconbitmap', path, bmp) - self + tk_call_without_enc('wm', 'iconbitmap', win.epath, bmp) + win else - image_obj(tk_call_without_enc('wm', 'iconbitmap', path)) + image_obj(tk_call_without_enc('wm', 'iconbitmap', win.epath)) end end + def iconbitmap(bmp=nil) + Wm.iconbitmap(self, bmp) + end + alias wm_iconbitmap iconbitmap TOPLEVEL_METHODCALL_OPTKEYS['iconbitmap'] = 'iconbitmap' - def iconphoto(*imgs) + def Wm.iconphoto(win, *imgs) if imgs.empty? - @wm_iconphoto = nil unless defined? @wm_iconphoto - return @wm_iconphoto + win.instance_eval{ + @wm_iconphoto = nil unless defined? @wm_iconphoto + return @wm_iconphoto + } end imgs = imgs[0] if imgs.length == 1 && imgs[0].kind_of?(Array) - tk_call_without_enc('wm', 'iconphoto', path, *imgs) - @wm_iconphoto = imgs - self + tk_call_without_enc('wm', 'iconphoto', win.epath, *imgs) + win.instance_eval{ @wm_iconphoto = imgs } + win + end + def iconphoto(*imgs) + Wm.iconphoto(self, *imgs) end + alias wm_iconphoto iconphoto TOPLEVEL_METHODCALL_OPTKEYS['iconphoto'] = 'iconphoto' - def iconphoto_default(*imgs) + def Wm.iconphoto_default(win, *imgs) imgs = imgs[0] if imgs.length == 1 && imgs[0].kind_of?(Array) - tk_call_without_enc('wm', 'iconphoto', path, '-default', *imgs) - self + tk_call_without_enc('wm', 'iconphoto', win.epath, '-default', *imgs) + win + end + def iconphoto_default(*imgs) + Wm.iconphoto_default(self, *imgs) end + alias wm_iconphoto_default iconphoto_default - def iconify(ex = true) + def Wm.iconify(win, ex = true) if ex - tk_call_without_enc('wm', 'iconify', path) + tk_call_without_enc('wm', 'iconify', win.epath) else - self.deiconify + Wm.deiconify(win) end - self + win + end + def iconify(ex = true) + Wm.iconify(self, ex) end + alias wm_iconify iconify - def iconmask(bmp=nil) + def Wm.iconmask(win, bmp=nil) if bmp - tk_call_without_enc('wm', 'iconmask', path, bmp) - self + tk_call_without_enc('wm', 'iconmask', win.epath, bmp) + win else - image_obj(tk_call_without_enc('wm', 'iconmask', path)) + image_obj(tk_call_without_enc('wm', 'iconmask', win.epath)) end end + def iconmask(bmp=nil) + Wm.iconmask(self, bmp) + end + alias wm_iconmask iconmask TOPLEVEL_METHODCALL_OPTKEYS['iconmask'] = 'iconmask' - def iconname(name=nil) + def Wm.iconname(win, name=nil) if name - tk_call('wm', 'iconname', path, name) - self + tk_call('wm', 'iconname', win.epath, name) + win else - tk_call('wm', 'iconname', path) + tk_call('wm', 'iconname', win.epath) end end + def iconname(name=nil) + Wm.iconname(self, name) + end + alias wm_iconname iconname TOPLEVEL_METHODCALL_OPTKEYS['iconname'] = 'iconname' - def iconposition(*args) + def Wm.iconposition(win, *args) if args.size == 0 - list(tk_call_without_enc('wm', 'iconposition', path)) + list(tk_call_without_enc('wm', 'iconposition', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call_without_enc('wm', 'iconposition', path, *args) - self + tk_call_without_enc('wm', 'iconposition', win.epath, *args) + win end end + def iconposition(*args) + Wm.iconposition(self, *args) + end + alias wm_iconposition iconposition TOPLEVEL_METHODCALL_OPTKEYS['iconposition'] = 'iconposition' - def iconwindow(win = nil) - if win - tk_call_without_enc('wm', 'iconwindow', path, win) - self + def Wm.iconwindow(win, iconwin = nil) + if iconwin + tk_call_without_enc('wm', 'iconwindow', win.epath, iconwin) + win else - w = tk_call_without_enc('wm', 'iconwindow', path) + w = tk_call_without_enc('wm', 'iconwindow', win.epath) (w == '')? nil: window(w) end end + def iconwindow(iconwin = nil) + Wm.iconwindow(self, iconwin) + end + alias wm_iconwindow iconwindow TOPLEVEL_METHODCALL_OPTKEYS['iconwindow'] = 'iconwindow' - def maxsize(*args) + def Wm.manage(win) + # Tcl/Tk 8.5+ feature + tk_call_without_enc('wm', 'manage', win.epath) + win + end + def wm_manage + Wm.manage(self) + end +=begin + def Wm.manage(win, use_id = nil) + # Tcl/Tk 8.5+ feature + # -------------------------------------------------------------- + # In the future release, I want to support to embed the 'win' + # into the container which has window-id 'use-id'. + # It may give users frexibility on controlling their GUI. + # However, it may be difficult for current Tcl/Tk (Tcl/Tk8.5.1), + # because it seems to require to modify Tcl/Tk's source code. + # -------------------------------------------------------------- + if use_id + tk_call_without_enc('wm', 'manage', win.epath, '-use', use_id) + else + tk_call_without_enc('wm', 'manage', win.epath) + end + win + end +=end + + def Wm.maxsize(win, *args) if args.size == 0 - list(tk_call_without_enc('wm', 'maxsize', path)) + list(tk_call_without_enc('wm', 'maxsize', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call_without_enc('wm', 'maxsize', path, *args) - self + tk_call_without_enc('wm', 'maxsize', win.epath, *args) + win end end + def maxsize(*args) + Wm.maxsize(self, *args) + end + alias wm_maxsize maxsize TOPLEVEL_METHODCALL_OPTKEYS['maxsize'] = 'maxsize' - def minsize(*args) + def Wm.minsize(win, *args) if args.size == 0 - list(tk_call_without_enc('wm', 'minsize', path)) + list(tk_call_without_enc('wm', 'minsize', win.epath)) else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call_without_enc('wm', 'minsize', path, *args) - self + tk_call_without_enc('wm', 'minsize', win.path, *args) + win end end + def minsize(*args) + Wm.minsize(self, *args) + end + alias wm_minsize minsize TOPLEVEL_METHODCALL_OPTKEYS['minsize'] = 'minsize' - def overrideredirect(mode=None) - if mode == None - bool(tk_call_without_enc('wm', 'overrideredirect', path)) + def Wm.overrideredirect(win, mode=TkComm::None) + if mode == TkComm::None + bool(tk_call_without_enc('wm', 'overrideredirect', win.epath)) else - tk_call_without_enc('wm', 'overrideredirect', path, mode) - self + tk_call_without_enc('wm', 'overrideredirect', win.epath, mode) + win end end + def overrideredirect(mode=TkComm::None) + Wm.overrideredirect(self, mode=TkComm::None) + end + alias wm_overrideredirect overrideredirect TOPLEVEL_METHODCALL_OPTKEYS['overrideredirect'] = 'overrideredirect' - def positionfrom(who=None) - if who == None - r = tk_call_without_enc('wm', 'positionfrom', path) + def Wm.positionfrom(win, who=TkComm::None) + if who == TkComm::None + r = tk_call_without_enc('wm', 'positionfrom', win.epath) (r == "")? nil: r else - tk_call_without_enc('wm', 'positionfrom', path, who) - self + tk_call_without_enc('wm', 'positionfrom', win.epath, who) + win end end + def positionfrom(who=TkComm::None) + Wm.positionfrom(self, who) + end + alias wm_positionfrom positionfrom TOPLEVEL_METHODCALL_OPTKEYS['positionfrom'] = 'positionfrom' - def protocol(name=nil, cmd=nil, &b) + def Wm.protocol(win, name=nil, cmd=nil, &b) if cmd - tk_call_without_enc('wm', 'protocol', path, name, cmd) - self + tk_call_without_enc('wm', 'protocol', win.epath, name, cmd) + win elsif b - tk_call_without_enc('wm', 'protocol', path, name, proc(&b)) - self + tk_call_without_enc('wm', 'protocol', win.epath, name, proc(&b)) + win elsif name - result = tk_call_without_enc('wm', 'protocol', path, name) + result = tk_call_without_enc('wm', 'protocol', win.epath, name) (result == "")? nil : tk_tcl2ruby(result) else - tk_split_simplelist(tk_call_without_enc('wm', 'protocol', path)) + tk_split_simplelist(tk_call_without_enc('wm', 'protocol', win.epath)) end end + def protocol(name=nil, cmd=nil, &b) + Wm.protocol(self, name, cmd, &b) + end + alias wm_protocol protocol - def protocols(kv=nil) + def Wm.protocols(win, kv=nil) unless kv ret = {} - self.protocol.each{|name| - ret[name] = self.protocol(name) + Wm.protocol(win).each{|name| + ret[name] = Wm.protocol(win, name) } return ret end @@ -279,82 +413,140 @@ module Tk unless kv.kind_of?(Hash) fail ArgumentError, 'expect a hash of protocol=>command' end - kv.each{|k, v| self.protocol(k, v)} - self + kv.each{|k, v| Wm.protocol(win, k, v)} + win end + def protocols(kv=nil) + Wm.protocols(self, kv) + end + alias wm_protocols protocols TOPLEVEL_METHODCALL_OPTKEYS['protocols'] = 'protocols' - def resizable(*args) + def Wm.resizable(win, *args) if args.length == 0 - list(tk_call_without_enc('wm', 'resizable', path)).collect{|e| bool(e)} + list(tk_call_without_enc('wm', 'resizable', win.epath)).map!{|e| bool(e)} else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call_without_enc('wm', 'resizable', path, *args) - self + tk_call_without_enc('wm', 'resizable', win.epath, *args) + win end end + def resizable(*args) + Wm.resizable(self, *args) + end + alias wm_resizable resizable TOPLEVEL_METHODCALL_OPTKEYS['resizable'] = 'resizable' - def sizefrom(who=None) - if who == None - r = tk_call_without_enc('wm', 'sizefrom', path) + def Wm.sizefrom(win, who=TkComm::None) + if who == TkComm::None + r = tk_call_without_enc('wm', 'sizefrom', win.epath) (r == "")? nil: r else - tk_call_without_enc('wm', 'sizefrom', path, who) - self + tk_call_without_enc('wm', 'sizefrom', win.epath, who) + win end end + def sizefrom(who=TkComm::None) + Wm.sizefrom(self, who) + end + alias wm_sizefrom sizefrom TOPLEVEL_METHODCALL_OPTKEYS['sizefrom'] = 'sizefrom' + def Wm.stackorder(win) + list(tk_call('wm', 'stackorder', win.epath)) + end def stackorder - list(tk_call('wm', 'stackorder', path)) + Wm.stackorder(self) end + alias wm_stackorder stackorder - def stackorder_isabove(win) - bool(tk_call('wm', 'stackorder', path, 'isabove', win)) + def Wm.stackorder_isabove(win, target) + bool(tk_call('wm', 'stackorder', win.epath, 'isabove', target)) + end + def Wm.stackorder_is_above(win, target) + Wm.stackorder_isabove(win, target) + end + def stackorder_isabove(target) + Wm.stackorder_isabove(self, target) end + alias stackorder_is_above stackorder_isabove + alias wm_stackorder_isabove stackorder_isabove + alias wm_stackorder_is_above stackorder_isabove - def stackorder_isbelow(win) - bool(tk_call('wm', 'stackorder', path, 'isbelow', win)) + def Wm.stackorder_isbelow(win, target) + bool(tk_call('wm', 'stackorder', win.epath, 'isbelow', target)) end + def Wm.stackorder_is_below(win, target) + Wm.stackorder_isbelow(win, target) + end + def stackorder_isbelow(target) + Wm.stackorder_isbelow(self, target) + end + alias stackorder_is_below stackorder_isbelow + alias wm_stackorder_isbelow stackorder_isbelow + alias wm_stackorder_is_below stackorder_isbelow - def state(st=nil) + def Wm.state(win, st=nil) if st - tk_call_without_enc('wm', 'state', path, st) - self + tk_call_without_enc('wm', 'state', win.epath, st) + win else - tk_call_without_enc('wm', 'state', path) + tk_call_without_enc('wm', 'state', win.epath) end end + def state(st=nil) + Wm.state(self, st) + end + alias wm_state state TOPLEVEL_METHODCALL_OPTKEYS['state'] = 'state' - def title(str=nil) + def Wm.title(win, str=nil) if str - tk_call('wm', 'title', path, str) - self + tk_call('wm', 'title', win.epath, str) + win else - tk_call('wm', 'title', path) + tk_call('wm', 'title', win.epath) end end + def title(str=nil) + Wm.title(self, str) + end + alias wm_title title TOPLEVEL_METHODCALL_OPTKEYS['title'] = 'title' - def transient(master=nil) + def Wm.transient(win, master=nil) if master - tk_call_without_enc('wm', 'transient', path, master) - self + tk_call_without_enc('wm', 'transient', win.epath, master) + win else - window(tk_call_without_enc('wm', 'transient', path)) + window(tk_call_without_enc('wm', 'transient', win.epath)) end end + def transient(master=nil) + Wm.transient(self, master) + end + alias wm_transient transient TOPLEVEL_METHODCALL_OPTKEYS['transient'] = 'transient' - def withdraw(ex = true) + def Wm.withdraw(win, ex = true) if ex - tk_call_without_enc('wm', 'withdraw', path) + tk_call_without_enc('wm', 'withdraw', win.epath) else - self.deiconify + Wm.deiconify(win) end - self + win end + def withdraw(ex = true) + Wm.withdraw(self, ex) + end + alias wm_withdraw withdraw + end + + module Wm_for_General + Wm.instance_methods.each{|m| + if (m = m.to_s) =~ /^wm_(.*)$/ + eval "def #{m}(*args); Tk::Wm.#{$1}(self, *args); end" + end + } end end diff --git a/ext/tk/lib/tkextlib/SUPPORT_STATUS b/ext/tk/lib/tkextlib/SUPPORT_STATUS index 15925cba7..cfbe274c8 100644 --- a/ext/tk/lib/tkextlib/SUPPORT_STATUS +++ b/ext/tk/lib/tkextlib/SUPPORT_STATUS @@ -83,7 +83,7 @@ BLT 2.4z http://sourceforge.net/projects/blt TkTreeCtrl CVS/Hd(2005-12-02) http://sourceforge.net/projects/tktreectrl ==> treectrl -Tile 0.7.8 +Tile 0.8.0/8.5.1 http://sourceforge.net/projects/tktable ==> tile diff --git a/ext/tk/lib/tkextlib/blt/bitmap.rb b/ext/tk/lib/tkextlib/blt/bitmap.rb index 31cf8d422..23c6d2d06 100644 --- a/ext/tk/lib/tkextlib/blt/bitmap.rb +++ b/ext/tk/lib/tkextlib/blt/bitmap.rb @@ -13,7 +13,16 @@ module Tk::BLT TkCommandNames = ['::blt::bitmap'.freeze].freeze BITMAP_ID_TBL = TkCore::INTERP.create_table - BITMAP_ID = ['blt_bitmap_id'.freeze, '00000'.taint].freeze + + (BITMAP_ID = ['blt_bitmap_id'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + BITMAP_ID_TBL.mutex.synchronize{ BITMAP_ID_TBL.clear } + } def self.data(name) dat = tk_simple_list(tk_call('::blt::bitmap', 'data', name)) @@ -64,9 +73,13 @@ module Tk::BLT if name @id = name else - @id = BITMAP_ID.join(TkCore::INTERP._ip_id_) - BITMAP_ID[1].succ! - BITMAP_ID_TBL[@id] = self + BITMAP_ID.mutex.synchronize{ + @id = BITMAP_ID.join(TkCore::INTERP._ip_id_) + BITMAP_ID[1].succ! + } + BITMAP_ID_TBL.mutex.synchronize{ + BITMAP_ID_TBL[@id] = self + } end @path = @id diff --git a/ext/tk/lib/tkextlib/blt/component.rb b/ext/tk/lib/tkextlib/blt/component.rb index ad78a5430..dd387634e 100644 --- a/ext/tk/lib/tkextlib/blt/component.rb +++ b/ext/tk/lib/tkextlib/blt/component.rb @@ -327,13 +327,24 @@ module Tk::BLT ################# class Axis < TkObject - OBJ_ID = ['blt_chart_axis'.freeze, '00000'.taint].freeze - OBJ_TBL={} + (OBJ_ID = ['blt_chart_axis'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + AxisID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + AxisID_TBL.mutex.synchronize{ AxisID_TBL.clear } + } def self.id2obj(chart, id) cpath = chart.path - return id unless OBJ_TBL[cpath] - OBJ_TBL[cpath][id]? OBJ_TBL[cpath][id]: id + AxisID_TBL.mutex.synchronize{ + return id unless AxisID_TBL[cpath] + AxisID_TBL[cpath][id]? AxisID_TBL[cpath][id]: id + } end def self.new(chart, axis=nil, keys={}) @@ -341,12 +352,48 @@ module Tk::BLT keys = axis axis = nil end - OBJ_TBL[chart.path] = {} unless OBJ_TBL[chart.path] - return OBJ_TBL[chart.path][axis] if axis && OBJ_TBL[chart.path][axis] - super(chart, axis, keys) + if keys + keys = _symbolkey2str(keys) + not_create = keys.delete('without_creating') + else + not_create = false + end + + obj = nil + AxisID_TBL.mutex.synchronize{ + chart_path = chart.path + AxisID_TBL[chart_path] ||= {} + if axis && AxisID_TBL[chart_path][axis] + obj = AxisID_TBL[chart_path][axis] + else + (obj = self.allocate).instance_eval{ + if axis + @axis = @id = axis.to_s + else + OBJ_ID.mutex.synchronize{ + @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } + end + @path = @id + @parent = @chart = chart + @cpath = @chart.path + Axis::AxisID_TBL[@cpath][@axis] = self + unless not_create + tk_call(@chart, 'axis', 'create', @axis, keys) + return obj + end + } + end + } + + obj.configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, axis=nil, keys={}) + # dummy:: not called by 'new' method + if axis.kind_of?(Hash) keys = axis axis = nil @@ -354,13 +401,15 @@ module Tk::BLT if axis @axis = @id = axis.to_s else - @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze - OBJ_ID[1].succ! + OBJ_ID.mutex.synchronize{ + @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } end @path = @id @parent = @chart = chart @cpath = @chart.path - Axis::OBJ_TBL[@cpath][@axis] = self + # Axis::AxisID_TBL[@cpath][@axis] = self keys = _symbolkey2str(keys) unless keys.delete('without_creating') # @chart.axis_create(@axis, keys) @@ -438,17 +487,34 @@ module Tk::BLT ################# class Crosshairs < TkObject - OBJ_TBL={} + CrosshairsID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + CrosshairsID_TBL.mutex.synchronize{ CrosshairsID_TBL.clear } + } def self.new(chart, keys={}) - return OBJ_TBL[chart.path] if OBJ_TBL[chart.path] - super(chart, keys) + obj = nil + CrosshairsID_TBL.mutex.synchronize{ + unless (obj = CrosshairsID_TBL[chart.path]) + (obj = self.allocate).instance_eval{ + @parent = @chart = chart + @cpath = @chart.path + @path = @id = 'crosshairs' + Crosshairs::CrosshairsID_TBL[@cpath] = self + } + end + } + chart.crosshair_configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, keys={}) + # dummy:: not called by 'new' method + @parent = @chart = chart @cpath = @chart.path - Crosshairs::OBJ_TBL[@cpath] = self + # Crosshairs::CrosshairsID_TBL[@cpath] = self @chart.crosshair_configure(keys) unless keys.empty? @path = @id = 'crosshairs' end @@ -500,12 +566,18 @@ module Tk::BLT ElementTypeName = 'element' ElementTypeToClass = { ElementTypeName=>self } + ElementID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ ElementID_TBL.clear } + TkCore::INTERP.init_ip_env{ + ElementID_TBL.mutex.synchronize{ ElementID_TBL.clear } + } - OBJ_ID = ['blt_chart_element'.freeze, '00000'.taint].freeze - OBJ_TBL={} + (OBJ_ID = ['blt_chart_element'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } def Element.type2class(type) ElementTypeToClass[type] @@ -513,8 +585,10 @@ module Tk::BLT def Element.id2obj(chart, id) cpath = chart.path - return id unless OBJ_TBL[cpath] - OBJ_TBL[cpath][id]? OBJ_TBL[cpath][id]: id + ElementID_TBL.mutex.synchronize{ + return id unless ElementID_TBL[cpath] + ElementID_TBL[cpath][id]? ElementID_TBL[cpath][id]: id + } end def self.new(chart, element=nil, keys={}) @@ -522,14 +596,49 @@ module Tk::BLT keys = element element = nil end - OBJ_TBL[chart.path] = {} unless OBJ_TBL[chart.path] - if element && OBJ_TBL[chart.path][element] - return OBJ_TBL[chart.path][element] + if keys + keys = _symbolkey2str(keys) + not_create = keys.delete('without_creating') + else + not_create = false end - super(chart, element, keys) + + obj = nil + ElementID_TBL.mutex.synchronize{ + chart_path = chart.path + ElementID_TBL[chart_path] ||= {} + if element && ElementID_TBL[chart_path][element] + obj = ElementID_TBL[chart_path][element] + else + (obj = self.allocate).instance_eval{ + if element + @element = @id = element.to_s + else + OBJ_ID.mutex.synchronize{ + @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } + end + @path = @id + @parent = @chart = chart + @cpath = @chart.path + @typename = self.class::ElementTypeName + Element::ElementID_TBL[@cpath][@element] = self + unless not_create + tk_call(@chart, @typename, 'create', @element, keys) + return obj + end + } + end + } + + obj.configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, element=nil, keys={}) + # dummy:: not called by 'new' method + if element.kind_of?(Hash) keys = element element = nil @@ -537,14 +646,16 @@ module Tk::BLT if element @element = @id = element.to_s else - @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze - OBJ_ID[1].succ! + OBJ_ID.mutex.synchronize{ + @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } end @path = @id @parent = @chart = chart @cpath = @chart.path @typename = self.class::ElementTypeName - Element::OBJ_TBL[@cpath][@element] = self + # Element::ElementID_TBL[@cpath][@element] = self keys = _symbolkey2str(keys) unless keys.delete('without_creating') # @chart.element_create(@element, keys) @@ -622,17 +733,33 @@ module Tk::BLT ################# class GridLine < TkObject - OBJ_TBL={} + GridLineID_TBL = TkCore::INTERP.create_table + TkCore::INTERP.init_ip_env{ + GridLineID_TBL.mutex.synchronize{ GridLineID_TBL.clear } + } def self.new(chart, keys={}) - return OBJ_TBL[chart.path] if OBJ_TBL[chart.path] - super(chart, keys) + obj = nil + GridLineID_TBL.mutex.synchronize{ + unless (obj = GridLineID_TBL[chart.path]) + (obj = self.allocate).instance_eval{ + @parent = @chart = chart + @cpath = @chart.path + @path = @id = 'grid' + GridLine::GridLineID_TBL[@cpath] = self + } + end + } + chart.gridline_configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, keys={}) + # dummy:: not called by 'new' method + @parent = @chart = chart @cpath = @chart.path - GridLine::OBJ_TBL[@cpath] = self + # GridLine::GridLineID_TBL[@cpath] = self @chart.gridline_configure(keys) unless keys.empty? @path = @id = 'grid' end @@ -676,18 +803,35 @@ module Tk::BLT ################# class Legend < TkObject - OBJ_TBL={} + LegendID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + LegendID_TBL.mutex.synchronize{ LegendID_TBL.clear } + } def self.new(chart, keys={}) - return OBJ_TBL[chart.path] if OBJ_TBL[chart.path] - super(chart, keys) + obj = nil + LegenedID_TBL.mutex.synchronize{ + unless (obj = LegenedID_TBL[chart.path]) + (obj = self.allocate).instance_eval{ + @parent = @chart = chart + @cpath = @chart.path + @path = @id = 'crosshairs' + Legend::LegenedID_TBL[@cpath] = self + } + end + } + chart.legend_configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, keys={}) + # dummy:: not called by 'new' method + @parent = @chart = chart @cpath = @chart.path - Crosshairs::OBJ_TBL[@cpath] = self - @chart.crosshair_configure(keys) unless keys.empty? + # Legend::LegendID_TBL[@cpath] = self + @chart.legend_configure(keys) unless keys.empty? @path = @id = 'legend' end @@ -729,13 +873,24 @@ module Tk::BLT ################# class Pen < TkObject - OBJ_ID = ['blt_chart_pen'.freeze, '00000'.taint].freeze - OBJ_TBL={} + (OBJ_ID = ['blt_chart_pen'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + PenID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + PenID_TBL.mutex.synchronize{ PenID_TBL.clear } + } def self.id2obj(chart, id) cpath = chart.path - return id unless OBJ_TBL[cpath] - OBJ_TBL[cpath][id]? OBJ_TBL[cpath][id]: id + PenID_TBL.mutex.synchronize{ + return id unless PenID_TBL[cpath] + PenID_TBL[cpath][id]? PenID_TBL[cpath][id]: id + } end def self.new(chart, pen=nil, keys={}) @@ -743,9 +898,43 @@ module Tk::BLT keys = pen pen = nil end - OBJ_TBL[chart.path] = {} unless OBJ_TBL[chart.path] - return OBJ_TBL[chart.path][pen] if pen && OBJ_TBL[chart.path][pen] - super(chart, pen, keys) + if keys + keys = _symbolkey2str(keys) + not_create = keys.delete('without_creating') + else + not_create = false + end + + obj = nil + PenID_TBL.mutex.synchronize{ + chart_path = chart.path + PenID_TBL[chart_path] ||= {} + if pen && PenID_TBL[chart_path][pen] + obj = PenID_TBL[chart_path][pen] + else + (obj = self.allocate).instance_eval{ + if pen + @pen = @id = pen.to_s + else + OBJ_ID.mutex.synchronize{ + @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } + end + @path = @id + @parent = @chart = chart + @cpath = @chart.path + Pen::PenID_TBL[@cpath][@pen] = self + unless not_create + tk_call(@chart, 'pen', 'create', @pen, keys) + return obj + end + } + end + } + + obj.configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, pen=nil, keys={}) @@ -756,13 +945,15 @@ module Tk::BLT if pen @pen = @id = pen.to_s else - @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze - OBJ_ID[1].succ! + OBJ_ID.mutex.synchronize{ + @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } end @path = @id @parent = @chart = chart @cpath = @chart.path - Pen::OBJ_TBL[@cpath][@pen] = self + Pen::PenID_TBL[@cpath][@pen] = self keys = _symbolkey2str(keys) unless keys.delete('without_creating') # @chart.pen_create(@pen, keys) @@ -805,17 +996,34 @@ module Tk::BLT ################# class Postscript < TkObject - OBJ_TBL={} + PostscriptID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + PostscriptID_TBL.mutex.synchronize{ PostscriptID_TBL.clear } + } def self.new(chart, keys={}) - return OBJ_TBL[chart.path] if OBJ_TBL[chart.path] - super(chart, keys) + obj = nil + PostscriptID_TBL.mutex.synchronize{ + unless (obj = PostscriptID_TBL[chart.path]) + (obj = self.allocate).instance_eval{ + @parent = @chart = chart + @cpath = @chart.path + @path = @id = 'postscript' + Postscript::PostscriptID_TBL[@cpath] = self + } + end + } + chart.postscript_configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, keys={}) + # dummy:: not called by 'new' method + @parent = @chart = chart @cpath = @chart.path - Postscript::OBJ_TBL[@cpath] = self + # Postscript::PostscriptID_TBL[@cpath] = self @chart.postscript_configure(keys) unless keys.empty? @path = @id = 'postscript' end @@ -870,7 +1078,9 @@ module Tk::BLT MarkerTypeToClass = {} MarkerID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ MarkerID_TBL.clear } + TkCore::INTERP.init_ip_env{ + MarkerID_TBL.mutex.synchronize{ MarkerID_TBL.clear } + } def Marker.type2class(type) MarkerTypeToClass[type] @@ -878,8 +1088,13 @@ module Tk::BLT def Marker.id2obj(chart, id) cpath = chart.path - return id unless MarkerID_TBL[cpath] - MarkerID_TBL[cpath][id]? MarkerID_TBL[cpath][id]: id + MarkerID_TBL.mutex.synchronize{ + if MarkerID_TBL[cpath] + MarkerID_TBL[cpath][id]? MarkerID_TBL[cpath][id]: id + else + id + end + } end def self._parse_create_args(keys) @@ -943,10 +1158,10 @@ module Tk::BLT @parent = @chart = chart @cpath = chart.path @id = id - unless Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] - Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] = {} - end - Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self + Tk::BLT::PlotComponent::Marker::MarkerID_TBL.mutex.synchronize{ + Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] ||= {} + Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self + } } obj end @@ -956,10 +1171,10 @@ module Tk::BLT @cpath = parent.path @path = @id = create_self(*args) # an integer number as 'item id' - unless Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] - Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] = {} - end - Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self + Tk::BLT::PlotComponent::Marker::MarkerID_TBL.mutex.synchronize{ + Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] ||= {} + Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self + } end def create_self(*args) self.class.create(@chart, *args) # return an integer as 'item id' @@ -1037,14 +1252,14 @@ module Tk::BLT ################# def __destroy_hook__ - Axis::OBJ_TBL.delete(@path) - Crosshairs::OBJ_TBL.delete(@path) - Element::OBJ_TBL.delete(@path) - GridLine::OBJ_TBL.delete(@path) - Legend::OBJ_TBL.delete(@path) - Pen::OBJ_TBL.delete(@path) - Postscript::OBJ_TBL.delete(@path) - Marker::OBJ_TBL.delete(@path) + Axis::AxisID_TBL.delete(@path) + Crosshairs::CrosshairsID_TBL.delete(@path) + Element::ElementID_TBL.delete(@path) + GridLine::GridLineID_TBL.delete(@path) + Legend::LegendID_TBL.delete(@path) + Pen::PenID_TBL.delete(@path) + Postscript::PostscriptID_TBL.delete(@path) + Marker::MarkerID_TBL.delete(@path) super() end diff --git a/ext/tk/lib/tkextlib/blt/dragdrop.rb b/ext/tk/lib/tkextlib/blt/dragdrop.rb index 68fb9e591..98b1a4832 100644 --- a/ext/tk/lib/tkextlib/blt/dragdrop.rb +++ b/ext/tk/lib/tkextlib/blt/dragdrop.rb @@ -81,6 +81,22 @@ module Tk::BLT nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL) def self.ret_val(val) @@ -107,6 +123,22 @@ module Tk::BLT nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL) def self.ret_val(val) @@ -145,6 +177,22 @@ module Tk::BLT nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL) end diff --git a/ext/tk/lib/tkextlib/blt/tabset.rb b/ext/tk/lib/tkextlib/blt/tabset.rb index c26b6ee00..1a0f312c4 100644 --- a/ext/tk/lib/tkextlib/blt/tabset.rb +++ b/ext/tk/lib/tkextlib/blt/tabset.rb @@ -12,14 +12,26 @@ module Tk::BLT include TkTreatItemFont TabID_TBL = TkCore::INTERP.create_table - TabsetTab_ID = ['blt_tabset_tab'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TabID_TBL.clear } + (TabsetTab_ID = ['blt_tabset_tab'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + TabID_TBL.mutex.synchronize{ TabID_TBL.clear } + } def self.id2obj(tabset, id) tpath = tabset.path - return id unless TabID_TBL[tpath] - TabID_TBL[tpath][id]? TabID_TBL[tpath]: id + TabID_TBL.mutex.synchronize{ + if TabID_TBL[tpath] + TabID_TBL[tpath][id]? TabID_TBL[tpath]: id + else + id + end + } end def self.new(parent, pos=nil, name=nil, keys={}) @@ -32,12 +44,20 @@ module Tk::BLT keys = name name = nil end - - if name && TabID_TBL[parent.path] && TabID_TBL[parent.path][name] - TabID_TBL[parent.path][name] - else - super(parent, pos, name, keys) - end + obj = nil + TabID_TBL.mutex.synchronize{ + if name && TabID_TBL[parent.path] && TabID_TBL[parent.path][name] + obj = TabID_TBL[parent.path][name] + obj.configure if keys && ! keys.empty? + else + (obj = self.allocate).instance_eval{ + initialize(parent, pos, name, keys) + TabID_TBL[@tpath] = {} unless TabID_TBL[@tpath] + TabID_TBL[@tpath][@id] = self + } + end + } + obj end def initialize(parent, pos, name, keys) @@ -45,9 +65,6 @@ module Tk::BLT @tpath = parent.path if name @path = @id = name - TabID_TBL[@tpath] = {} unless TabID_TBL[@tpath] - TabID_TBL[@tpath][@id] = self - unless (list(tk_call(@tpath, 'tab', 'names', @id)).empty?) if pos idx = tk_call(@tpath, 'index', '-name', @id) @@ -58,18 +75,18 @@ module Tk::BLT end end tk_call(@tpath, 'tab', 'configure', @id, keys) - return + else + pos = 'end' unless pos + tk_call(@tpath, 'insert', pos, @id, keys) end - else - @path = @id = TabsetTab_ID.join(TkCore::INTERP._ip_id_) - TabID_TBL[@tpath] = {} unless TabID_TBL[@tpath] - TabID_TBL[@tpath][@id] = self - TabsetTab_ID[1].succ! + TabsetTab_ID.mutex.synchronize{ + @path = @id = TabsetTab_ID.join(TkCore::INTERP._ip_id_) + TabsetTab_ID[1].succ! + } + pos = 'end' unless pos + tk_call(@tpath, 'insert', pos, @id, keys) end - - pos = 'end' unless pos - tk_call(@tpath, 'insert', pos, @id, keys) end #def bind(context, cmd=Proc.new, *args) @@ -123,7 +140,9 @@ module Tk::BLT def delete() @t.delete(@id) - TabID_TBL[@tpath].delete(@id) + TabID_TBL.mutex.synchronize{ + TabID_TBL[@tpath].delete(@id) + } self end @@ -184,7 +203,9 @@ module Tk::BLT WidgetClassNames[WidgetClassName] = self def __destroy_hook__ - Tk::BLT::Tabset::Tab::TabID_TBL.delete(@path) + Tk::BLT::Tabset::Tab::TabID_TBL.mutex.synchronize{ + Tk::BLT::Tabset::Tab::TabID_TBL.delete(@path) + } end ######################################## @@ -291,11 +312,15 @@ module Tk::BLT def delete(first, last=None) tk_send('delete', tagindex(first), tagindex(last)) if first.kind_of?(Tk::BLT::Tabset::Tab) - TabID_TBL[@path].delete(first.id) + TabID_TBL.mutex.synchronize{ + TabID_TBL[@path].delete(first.id) + } end # middle tabs of the range are unknown if last.kind_of?(Tk::BLT::Tabset::Tab) - TabID_TBL[@path].delete(last.id) + TabID_TBL.mutex.synchronize{ + TabID_TBL[@path].delete(last.id) + } end self end diff --git a/ext/tk/lib/tkextlib/blt/tree.rb b/ext/tk/lib/tkextlib/blt/tree.rb index 07dc7ef7e..77b85f171 100644 --- a/ext/tk/lib/tkextlib/blt/tree.rb +++ b/ext/tk/lib/tkextlib/blt/tree.rb @@ -12,53 +12,77 @@ module Tk::BLT ################################### - class Node < TkObject + class Node < TkObject TreeNodeID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ TreeNodeID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + TreeNodeID_TBL.mutex.synchronize{ TreeNodeID_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless TreeNodeID_TBL[tpath] - if TreeNodeID_TBL[tpath][id] - TreeNodeID_TBL[tpath][id] - else - begin - self.new(tree, nil, 'node'=>Integer(id)) - rescue + TreeNodeID_TBL.mutex.synchronize{ + if TreeNodeID_TBL[tpath] + if TreeNodeID_TBL[tpath][id] + TreeNodeID_TBL[tpath][id] + else + begin + # self.new(tree, nil, 'node'=>Integer(id)) + id = Integer(id) + if bool(tk_call(@tpath, 'exists', id)) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = tpath + @path = @id = id + TreeNodeID_TBL[@tpath] = {} unless TreeNodeID_TBL[@tpath] + TreeNodeID_TBL[@tpath][@id] = self + } + obj + else + id + end + rescue + id + end + end + else id end - end + } end def self.new(tree, parent, keys={}) keys = _symbolkey2str(keys) tpath = tree.path - if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id]) - keys.delete('node') - tk_call(tree.path, 'move', id, parent, keys) if parent - return obj - end + TreeNodeID_TBL.mutex.synchronize{ + TreeNodeID_TBL[tpath] ||= {} + if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id]) + keys.delete('node') + tk_call(tree.path, 'move', id, parent, keys) if parent + return obj + end - super(tree, parent, keys) + (obj = self.allocate).instance_eval{ + initialize(tree, parent, keys) + TreeNodeID_TBL[tpath][@id] = self + } + obj + } end def initialize(tree, parent, keys={}) @parent = @tree = tree @tpath = @parent.path - parent = tk_call(@tpath, 'root') unless parent - if (id = keys['node']) && bool(tk_call(@tpath, 'exists', id)) @path = @id = id keys.delete('node') tk_call(@tpath, 'move', @id, parent, keys) if parent else + parent = tk_call(@tpath, 'root') unless parent @path = @id = tk_call(@tpath, 'insert', parent, keys) end - - TreeNodeID_TBL[@tpath] = {} unless TreeNodeID_TBL[@tpath] - TreeNodeID_TBL[@tpath][@id] = self end def id @@ -243,17 +267,42 @@ module Tk::BLT class Tag < TkObject TreeTagID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ TreeTagID_TBL.clear } - TreeTag_ID = ['blt_tree_tag'.freeze, '00000'.taint].freeze + + TkCore::INTERP.init_ip_env{ + TreeTagID_TBL.mutex.synchronize{ TreeTagID_TBL.clear } + } + + (TreeTag_ID = ['blt_tree_tag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } def self.id2obj(tree, id) tpath = tree.path - return id unless TreeTagID_TBL[tpath] - if TreeTagID_TBL[tpath][id] - TreeTagID_TBL[tpath][id] - else - self.new(tree, id) - end + TreeTagID_TBL.mutex.synchronize{ + if TreeTagID_TBL[tpath] + if TreeTagID_TBL[tpath][id] + TreeTagID_TBL[tpath][id] + else + begin + # self.new(tree, id) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = id.dup.freeze if id + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } + obj + rescue + id + end + end + else + id + end + } end def initialize(tree, tag_str = nil) @@ -263,12 +312,15 @@ module Tk::BLT if tag_str @path = @id = tag_str.dup.freeze else - @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_) - TreeTagID_TBL[@id] = self - TreeTag_ID[1].succ! + TreeTag_ID.mutex.synchronize{ + @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_) + TreeTag_ID[1].succ! + } end - TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] - TreeTagID_TBL[@tpath][@id] = self + TreeTagID_TBL.mutex.synchronize{ + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } end def id @@ -287,7 +339,9 @@ module Tk::BLT def forget() tk_call(@tpath, 'tag', 'forget', @id) - TreeTagID_TBL[@tpath].delete(@id) + TreeTagID_TBL.mutex.synchronize{ + TreeTagID_TBL[@tpath].delete(@id) + } self end @@ -312,44 +366,63 @@ module Tk::BLT class Notify < TkObject NotifyID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ NotifyID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + NotifyID_TBL.mutex.synchronize{ NotifyID_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless NotifyID_TBL[tpath] - if NotifyID_TBL[tpath][id] - NotifyID_TBL[tpath][id] - else - begin - self.new([tree, id]) - rescue - id + NotifyID_TBL.mutex.synchronize{ + if NotifyID_TBL[tpath] + if NotifyID_TBL[tpath][id] + NotifyID_TBL[tpath][id] + else + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = id + NotifyID_TBL[@tpath] ||= {} + NotifyID_TBL[@tpath][@id] = self + } + obj + end + else + return id end - end + } end def self.new(tree, *args, &b) - if tree.kind_of?(Array) - # not create - if obj = NotifyID_TBL[tree[0].path][tree[1]] + NotifyID_TBL.mutex.synchronize{ + if tree.kind_of?(Array) + # not create + tpath = tree[0].path + NotifyID_TBL[tpath] ||= {} + unless (obj = NotifyID_TBL[tpath][tree[1]]) + (NotifyID_TBL[tpath][tree[1]] = + obj = self.allocate).instance_eval{ + @parent = @tree = tree[0] + @tpath = @parent.path + @path = @id = tree[1] + } + end return obj - else - return super(false, tree[0], tree[1]) end - end - super(true, tree, *args, &b) + (obj = self.allocate).instance_eval{ + initialize(tree, *args, &b) + NotifyID_TBL[@tpath] ||= {} + NotifyID_TBL[@tpath][@id] = self + } + return obj + } end - def initialize(create, tree, *args, &b) + def initialize(tree, *args, &b) @parent = @tree = tree @tpath = @parent.path - unless create - @path = @id = args[0] - return - end - # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) cmd = args.shift @@ -378,7 +451,9 @@ module Tk::BLT def delete() tk_call(@tpath, 'notify', 'delete', @id) - NotifyID_TBL[tpath].delete(@id) + NotifyID_TBL.mutex.synchronize{ + NotifyID_TBL[@tpath].delete(@id) + } self end @@ -395,44 +470,69 @@ module Tk::BLT class Trace < TkObject TraceID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ TraceID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + TraceID_TBL.mutex.synchronize{ TraceID_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless TraceID_TBL[tpath] - if TraceID_TBL[tpath][id] - TraceID_TBL[tpath][id] - else - begin - self.new([tree, id]) - rescue + TraceID_TBL.mutex.synchronize{ + if TraceID_TBL[tpath] + if TraceID_TBL[tpath][id] + TraceID_TBL[tpath][id] + else + begin + # self.new([tree, id]) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = node # == traceID + TraceID_TBL[@tpath] ||= {} + TraceID_TBL[@tpath][@id] = self + } + obj + rescue + id + end + end + else id end - end + } end def self.new(tree, *args, &b) - if tree.kind_of?(Array) - # not create - if obj = TraceID_TBL[tree[0].path][tree[1]] + TraceID_TBL.mutex.synchronize{ + if tree.kind_of?(Array) + # not create + tpath = tree[0].path + TraceID_TBL[tpath] ||= {} + unless (obj = TraceID_TBL[tpath][tree[1]]) + (TraceID_TBL[tpath][tree[1]] = + obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = tree[1] # == traceID + } + end return obj - else - return super(false, tree[0], tree[1]) end - end - super(true, tree, *args, &b) + # super(true, tree, *args, &b) + (obj = self.allocate).instance_eval{ + initialize(tree, *args, &b) + TraceID_TBL[@tpath] ||= {} + TraceID_TBL[@tpath][@id] = self + } + return obj + } end - def initialize(create, tree, node, key, opts, cmd=nil, &b) + def initialize(tree, node, key, opts, cmd=nil, &b) @parent = @tree = tree @tpath = @parent.path - unless create - @path = @id = node # == traceID - return - end - if !cmd if b cmd = Proc.new(&b) @@ -459,7 +559,9 @@ module Tk::BLT def delete() tk_call(@tpath, 'trace', 'delete', @id) - TraceID_TBL[tpath].delete(@id) + TraceID_TBL.mutex.synchronize{ + TraceID_TBL[tpath].delete(@id) + } self end @@ -475,7 +577,12 @@ module Tk::BLT ################################### TreeID_TBL = TkCore::INTERP.create_table - Tree_ID = ['blt_tree'.freeze, '00000'.taint].freeze + + (Tree_ID = ['blt_tree'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } def __keyonly_optkeys { @@ -498,7 +605,9 @@ module Tk::BLT end def self.id2obj(id) - TreeID_TBL[id]? TreeID_TBL[id]: id + TreeID_TBL.mutex.synchronize{ + TreeID_TBL[id]? TreeID_TBL[id]: id + } end def self.names(pat = None) @@ -513,27 +622,45 @@ module Tk::BLT end def self.new(name = nil) - return TreeID_TBL[name] if name && TreeID_TBL[name] - super(name) + TreeID_TBL.mutex.synchronize{ + if name && TreeID_TBL[name] + TreeID_TBL[name] + else + (obj = self.allocate).instance_eval{ + initialize(name) + TreeID_TBL[@id] = self + } + obj + end + } end def initialzie(name = nil) if name @path = @id = name else - @path = @id = Tree_ID.join(TkCore::INTERP._ip_id_) - TreeID_TBL[@id] = self - Tree_ID[1].succ! + Tree_ID.mutex.synchronize{ + @path = @id = Tree_ID.join(TkCore::INTERP._ip_id_) + Tree_ID[1].succ! + } end - TreeID_TBL[@id] = self + tk_call('::blt::tree', 'create', @id) end def __destroy_hook__ - Tk::BLT::Tree::Node::TreeNodeID_TBL.delete(@path) - Tk::BLT::Tree::Tag::TreeTagID_TBL.delete(@path) - Tk::BLT::Tree::Notify::NotifyID_TBL.delete(@path) - Tk::BLT::Tree::Trace::TraceID_TBL.delete(@path) + Tk::BLT::Tree::Node::TreeNodeID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Node::TreeNodeID_TBL.delete(@path) + } + Tk::BLT::Tree::Tag::TreeTagID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Tag::TreeTagID_TBL.delete(@path) + } + Tk::BLT::Tree::Notify::NotifyID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Notify::NotifyID_TBL.delete(@path) + } + Tk::BLT::Tree::Trace::TraceID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Trace::TraceID_TBL.delete(@path) + } end def tagid(tag) @@ -592,12 +719,14 @@ module Tk::BLT def delete(*nodes) tk_call('::blt::tree', 'delete', *(nodes.collect{|node| tagid(node)})) - nodes.each{|node| - if node.kind_of?(Tk::BLT::Tree::Node) - Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.id) - else - Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.to_s) - end + Tk::BLT::Tree::Node::TreeNodeID_TBL.mutex.synchronize{ + nodes.each{|node| + if node.kind_of?(Tk::BLT::Tree::Node) + Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.id) + else + Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.to_s) + end + } } self end @@ -728,7 +857,9 @@ module Tk::BLT id.delete else tk_call(@path, 'notify', 'delete', id) - Tk::BLT::Tree::Notify::NotifyID_TBL[@path].delete(id.to_s) + Tk::BLT::Tree::Notify::NotifyID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Notify::NotifyID_TBL[@path].delete(id.to_s) + } end self end @@ -835,7 +966,9 @@ module Tk::BLT def tag_forget(tag) tag = tag.id if tag.kind_of?(Tk::BLT::Tree::Tag) tk_call(@path, 'tag', 'forget', tag) - TreeTagID_TBL[@path].delete(tag) + TreeTagID_TBL.mutex.synchronize{ + TreeTagID_TBL[@path].delete(tag) + } self end @@ -889,7 +1022,9 @@ module Tk::BLT def trace_delete(*args) args = args.collect{|id| tagid(id)} tk_call(@path, 'trace', 'delete', *args) - args.each{|id| Tk::BLT::Tree::Trace::TraceID_TBL[@path].delete(id.to_s)} + Tk::BLT::Tree::Trace::TraceID_TBL.mutex.synchronize{ + args.each{|id| Tk::BLT::Tree::Trace::TraceID_TBL[@path].delete(id.to_s)} + } self end diff --git a/ext/tk/lib/tkextlib/blt/treeview.rb b/ext/tk/lib/tkextlib/blt/treeview.rb index 0343d28b9..fc890614b 100644 --- a/ext/tk/lib/tkextlib/blt/treeview.rb +++ b/ext/tk/lib/tkextlib/blt/treeview.rb @@ -239,6 +239,22 @@ class Tk::BLT::Treeview nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -273,8 +289,12 @@ class Tk::BLT::Treeview ######################## def __destroy_hook__ - Tk::BLT::Treeview::Node::TreeNodeID_TBL.delete(@path) - Tk::BLT::Treeview::Tag::TreeTagID_TBL.delete(@path) + Tk::BLT::Treeview::Node::TreeNodeID_TBL.mutex.synchronize{ + Tk::BLT::Treeview::Node::TreeNodeID_TBL.delete(@path) + } + Tk::BLT::Treeview::Tag::TreeTagID_TBL.mutex.synchronize{ + Tk::BLT::Treeview::Tag::TreeTagID_TBL.delete(@path) + } end def tagid(tag) @@ -472,6 +492,22 @@ class Tk::BLT::Treeview nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -967,22 +1003,47 @@ class Tk::BLT::Treeview::Node < TkObject include Tk::BLT::Treeview::TagOrID_Methods TreeNodeID_TBL = TkCore::INTERP.create_table - TreeNode_ID = ['blt_treeview_node'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TreeNodeID_TBL.clear } + (TreeNode_ID = ['blt_treeview_node'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + TreeNodeID_TBL.mutex.synchronize{ TreeNodeID_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless TreeNodeID_TBL[tpath] - if TreeNodeID_TBL[tpath][id] - TreeNodeID_TBL[tpath][id] - else - begin - self.new(tree, nil, nil, 'node'=>Integer(id)) - rescue + TreeNodeID_TBL.mutex.synchronize{ + if TreeNodeID_TBL[tpath] + if TreeNodeID_TBL[tpath][id] + TreeNodeID_TBL[tpath][id] + else + begin + # self.new(tree, nil, nil, 'node'=>Integer(id)) + unless (tk_call(@tpath, 'get', id)).empty? + id = Integer(id) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = id + TreeNodeID_TBL[@tpath] ||= {} + TreeNodeID_TBL[@tpath][@id] = self + } + obj + else + id + end + rescue + id + end + end + else id end - end + } end def self.new(tree, pos, parent=nil, keys={}) @@ -994,13 +1055,21 @@ class Tk::BLT::Treeview::Node < TkObject keys = _symbolkey2str(keys) tpath = tree.path - if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id]) - keys.delete('node') - tk_call(tree.path, 'move', id, pos, parent) if parent - return obj - end + TreeNodeID_TBL.mutex.synchronize{ + TreeNodeID_TBL[tpath] ||= {} + if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id]) + keys.delete('node') + tk_call(tree.path, 'move', id, pos, parent) if parent + return obj + end - super(tree, pos, parent, keys) + #super(tree, pos, parent, keys) + (obj = self.allocate).instance_eval{ + initialize(tree, pos, parent, keys) + TreeNodeID_TBL[tpath][@id] = self + } + obj + } end def initialize(tree, pos, parent, keys) @@ -1008,11 +1077,18 @@ class Tk::BLT::Treeview::Node < TkObject @tpath = @parent.path if (id = keys['node']) + # if tk_call(@tpath, 'get', id).empty? + # fail RuntimeError, "not exist the node '#{id}'" + # end @path = @id = id tk_call(@tpath, 'move', @id, pos, tagid(parent)) if parent + configure(keys) if keys && ! keys.empty? else - name = TreeNode_ID.join(TkCore::INTERP._ip_id_).freeze - TreeNode_ID[1].succ! + name = nil + TreeNode_ID.mutex.synchronize{ + name = TreeNode_ID.join(TkCore::INTERP._ip_id_).freeze + TreeNode_ID[1].succ! + } at = keys.delete['at'] @@ -1035,9 +1111,6 @@ class Tk::BLT::Treeview::Node < TkObject end @path = @id end - - TreeNodeID_TBL[@tpath] = {} unless TreeNodeID_TBL[@tpath] - TreeNodeID_TBL[@tpath][@id] = self end def id @@ -1051,37 +1124,66 @@ class Tk::BLT::Treeview::Tag < TkObject include Tk::BLT::Treeview::TagOrID_Methods TreeTagID_TBL = TkCore::INTERP.create_table - TreeTag_ID = ['blt_treeview_tag'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TreeTagID_TBL.clear } + (TreeTag_ID = ['blt_treeview_tag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } - def self.id2obj(tree, id) + TkCore::INTERP.init_ip_env{ + TreeTagID_TBL.mutex.synchronize{ TreeTagID_TBL.clear } + } + + def self.id2obj(tree, name) tpath = tree.path - return id unless TreeTagID_TBL[tpath] - if TreeTagID_TBL[tpath][id] - TreeTagID_TBL[tpath][id] - else - begin - self.new(tree, nil, nil, 'name'=>Integer(id)) - rescue + TreeTagID_TBL.mutex.synchronize{ + if TreeTagID_TBL[tpath] + if TreeTagID_TBL[tpath][name] + TreeTagID_TBL[tpath][name] + else + #self.new(tree, name) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = name + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } + obj + end + else id end - end + } end def self.new_by_name(tree, name, *ids) - if (obj = TreeTagID_TBL[tree.path][name]) - return obj - end - new([tree, name], ids) + TreeTagID_TBL.mutex.synchronize{ + unless (obj = TreeTagID_TBL[tree.path][name]) + (obj = self.allocate).instance_eval{ + initialize(tree, name, ids) + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } + end + obj + } end def self.new(tree, *ids) - if tree.kind_of?(Array) - super(tree[0], tree[1], ids) - else - super(tree, nil, ids) - end + TreeTagID_TBL.mutex.synchronize{ + (obj = self.allocate).instance_eval{ + if tree.kind_of?(Array) + initialize(tree[0], tree[1], ids) + else + initialize(tree, nil, ids) + end + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } + obj + } end def initialize(tree, name, ids) @@ -1091,13 +1193,12 @@ class Tk::BLT::Treeview::Tag < TkObject if name @path = @id = name else - @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_).freeze - TreeTag_ID[1].succ! + TreeTag_ID.mutex.synchronize{ + @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_).freeze + TreeTag_ID[1].succ! + } end - TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] - TreeTagID_TBL[@tpath][@id] = self - unless ids.empty? tk_call(@tpath, 'tag', 'add', @id, *(ids.collect{|id| tagid(id)})) end diff --git a/ext/tk/lib/tkextlib/blt/vector.rb b/ext/tk/lib/tkextlib/blt/vector.rb index 540b6b910..76c12a24e 100644 --- a/ext/tk/lib/tkextlib/blt/vector.rb +++ b/ext/tk/lib/tkextlib/blt/vector.rb @@ -23,14 +23,17 @@ module Tk::BLT end def self.names(pat=None) - simplelist(tk_call('::blt::vector', 'names', pat)).collect{|name| - if TkVar_ID_TBL[name] - TkVar_ID_TBL[name] - elsif name[0..1] == '::' && TkVar_ID_TBL[name[2..-1]] - TkVar_ID_TBL[name[2..-1]] - else - name - end + list = simplelist(tk_call('::blt::vector', 'names', pat)) + TkVar_ID_TBL.mutex.synchronize{ + list.collect{|name| + if TkVar_ID_TBL[name] + TkVar_ID_TBL[name] + elsif name[0..1] == '::' && TkVar_ID_TBL[name[2..-1]] + TkVar_ID_TBL[name[2..-1]] + else + name + end + } } end @@ -53,7 +56,9 @@ module Tk::BLT "#auto", *hash_kv(keys)) end - TkVar_ID_TBL[@id] = self + TkVar_ID_TBL.mutex.synchronize{ + TkVar_ID_TBL[@id] = self + } @def_default = false @default_val = nil @@ -221,13 +226,21 @@ module Tk::BLT class VectorAccess < Vector def self.new(name) - return TkVar_ID_TBL[name] if TkVar_ID_TBL[name] - super(name, size=nil, keys={}) + TkVar_ID_TBL.mutex.synchronize{ + if TkVar_ID_TBL[name] + TkVar_ID_TBL[name] + else + (obj = self.allocate).instance_eval{ + initialize(name) + TkVar_ID_TBL[@id] = self + } + obj + end + } end def initialize(vec_name) @id = vec_name - TkVar_ID_TBL[@id] = self @def_default = false @default_val = nil diff --git a/ext/tk/lib/tkextlib/blt/watch.rb b/ext/tk/lib/tkextlib/blt/watch.rb index ae5e50f12..2daf417e0 100644 --- a/ext/tk/lib/tkextlib/blt/watch.rb +++ b/ext/tk/lib/tkextlib/blt/watch.rb @@ -13,11 +13,23 @@ module Tk::BLT TkCommandNames = ['::blt::watch'.freeze].freeze WATCH_ID_TBL = TkCore::INTERP.create_table - BLT_WATCH_ID = ['blt_watch_id'.freeze, '00000'.taint].freeze + + (BLT_WATCH_ID = ['blt_watch_id'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + WATCH_ID_TBL.mutex.synchronize{ WATCH_ID_TBL.clear } + } def self.names(state = None) - tk_split_list(tk_call('::blt::watch', 'names', state)).collect{|name| - WATCH_ID_TBL[name] || name + lst = tk_split_list(tk_call('::blt::watch', 'names', state)) + WATCH_ID_TBL.mutex.synchronize{ + lst.collect{|name| + WATCH_ID_TBL[name] || name + } } end @@ -45,13 +57,17 @@ module Tk::BLT if name @id = name.to_s else - @id = BLT_WATCH_ID.join(TkCore::INTERP._ip_id_) - BLT_WATCH_ID[1].succ! + BLT_WATCH_ID.mutex.synchronize{ + @id = BLT_WATCH_ID.join(TkCore::INTERP._ip_id_) + BLT_WATCH_ID[1].succ! + } end @path = @id - WATCH_ID_TBL[@id] = self + WATCH_ID_TBL.mutex.synchronize{ + WATCH_ID_TBL[@id] = self + } tk_call('::blt::watch', 'create', @id, *hash_kv(keys)) end diff --git a/ext/tk/lib/tkextlib/bwidget/buttonbox.rb b/ext/tk/lib/tkextlib/bwidget/buttonbox.rb index a8f23e874..8d6d21218 100644 --- a/ext/tk/lib/tkextlib/bwidget/buttonbox.rb +++ b/ext/tk/lib/tkextlib/bwidget/buttonbox.rb @@ -40,7 +40,13 @@ class Tk::BWidget::ButtonBox def add(keys={}, &b) win = window(tk_send('add', *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end @@ -62,7 +68,13 @@ class Tk::BWidget::ButtonBox def insert(idx, keys={}, &b) win = window(tk_send('insert', tagid(idx), *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/combobox.rb b/ext/tk/lib/tkextlib/bwidget/combobox.rb index 31f71c3aa..1c58a4ccb 100644 --- a/ext/tk/lib/tkextlib/bwidget/combobox.rb +++ b/ext/tk/lib/tkextlib/bwidget/combobox.rb @@ -25,7 +25,13 @@ class Tk::BWidget::ComboBox def get_listbox(&b) win = window(tk_send_without_enc('getlistbox')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/dialog.rb b/ext/tk/lib/tkextlib/bwidget/dialog.rb index ae5f0238a..0ddee21d0 100644 --- a/ext/tk/lib/tkextlib/bwidget/dialog.rb +++ b/ext/tk/lib/tkextlib/bwidget/dialog.rb @@ -112,19 +112,37 @@ class Tk::BWidget::Dialog def add(keys={}, &b) win = window(tk_send('add', *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_frame(&b) win = window(tk_send('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_buttonbox(&b) win = window(@path + '.bbox') - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/labelframe.rb b/ext/tk/lib/tkextlib/bwidget/labelframe.rb index f7b267eeb..dc221806e 100644 --- a/ext/tk/lib/tkextlib/bwidget/labelframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/labelframe.rb @@ -40,7 +40,13 @@ class Tk::BWidget::LabelFrame end def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end end diff --git a/ext/tk/lib/tkextlib/bwidget/listbox.rb b/ext/tk/lib/tkextlib/bwidget/listbox.rb index 126750066..d8cd72fec 100644 --- a/ext/tk/lib/tkextlib/bwidget/listbox.rb +++ b/ext/tk/lib/tkextlib/bwidget/listbox.rb @@ -211,14 +211,26 @@ class Tk::BWidget::ListBox::Item include TkTreatTagFont ListItem_TBL = TkCore::INTERP.create_table - ListItem_ID = ['bw:item'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ ListItem_TBL.clear } + (ListItem_ID = ['bw:item'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + ListItem_TBL.mutex.synchronize{ ListItem_TBL.clear } + } def self.id2obj(lbox, id) lpath = lbox.path - return id unless ListItem_TBL[lpath] - ListItem_TBL[lpath][id]? ListItem_TBL[lpath][id]: id + ListItem_TBL.mutex.synchronize{ + if ListItem_TBL[lpath] + ListItem_TBL[lpath][id]? ListItem_TBL[lpath][id]: id + else + id + end + } end def initialize(lbox, *args) @@ -250,13 +262,17 @@ class Tk::BWidget::ListBox::Item if keys.key?('itemname') @path = @id = keys.delete('itemname') else - @path = @id = ListItem_ID.join(TkCore::INTERP._ip_id_) - ListItem_ID[1].succ! + ListItem_ID.mutex.synchronize{ + @path = @id = ListItem_ID.join(TkCore::INTERP._ip_id_) + ListItem_ID[1].succ! + } end - ListItem_TBL[@id] = self - ListItem_TBL[@lpath] = {} unless ListItem_TBL[@lpath] - ListItem_TBL[@lpath][@id] = self + ListItem_TBL.mutex.synchronize{ + ListItem_TBL[@id] = self + ListItem_TBL[@lpath] = {} unless ListItem_TBL[@lpath] + ListItem_TBL[@lpath][@id] = self + } @listbox.insert(index, @id, keys) end diff --git a/ext/tk/lib/tkextlib/bwidget/mainframe.rb b/ext/tk/lib/tkextlib/bwidget/mainframe.rb index c54e87855..de66eaf81 100644 --- a/ext/tk/lib/tkextlib/bwidget/mainframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/mainframe.rb @@ -41,37 +41,73 @@ class Tk::BWidget::MainFrame def add_indicator(keys={}, &b) win = window(tk_send('addindicator', *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def add_toolbar(&b) win = window(tk_send('addtoolbar')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_frame(&b) win = window(tk_send('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_indicator(idx, &b) win = window(tk_send('getindicator', idx)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_menu(menu_id, &b) win = window(tk_send('getmenu', menu_id)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_toolbar(idx, &b) win = window(tk_send('gettoolbar', idx)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/messagedlg.rb b/ext/tk/lib/tkextlib/bwidget/messagedlg.rb index 9c946d063..cc8a996f4 100644 --- a/ext/tk/lib/tkextlib/bwidget/messagedlg.rb +++ b/ext/tk/lib/tkextlib/bwidget/messagedlg.rb @@ -173,6 +173,9 @@ class Tk::BWidget::MessageDlg end def create - num_or_str(tk_call(self.class::TkCommandNames[0], @path, *hash_kv(@keys))) + # return the index of the pressed button, or nil if it is destroyed + ret = num_or_str(tk_call(self.class::TkCommandNames[0], + @path, *hash_kv(@keys))) + (ret < 0)? nil: ret end end diff --git a/ext/tk/lib/tkextlib/bwidget/notebook.rb b/ext/tk/lib/tkextlib/bwidget/notebook.rb index 5146d4915..423943619 100644 --- a/ext/tk/lib/tkextlib/bwidget/notebook.rb +++ b/ext/tk/lib/tkextlib/bwidget/notebook.rb @@ -89,7 +89,13 @@ class Tk::BWidget::NoteBook def add(page, &b) win = window(tk_send('add', tagid(page))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end @@ -105,7 +111,13 @@ class Tk::BWidget::NoteBook def get_frame(page, &b) win = window(tk_send('getframe', tagid(page))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end @@ -115,7 +127,13 @@ class Tk::BWidget::NoteBook def insert(index, page, keys={}, &b) win = window(tk_send('insert', index, tagid(page), *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb b/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb index fc01284be..fbc2c1125 100644 --- a/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb +++ b/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb @@ -26,7 +26,13 @@ class Tk::BWidget::PagesManager def add(page, &b) win = window(tk_send('add', tagid(page))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end @@ -42,7 +48,13 @@ class Tk::BWidget::PagesManager def get_frame(page, &b) win = window(tk_send('getframe', tagid(page))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/panedwindow.rb b/ext/tk/lib/tkextlib/bwidget/panedwindow.rb index 19982c609..4d979fd52 100644 --- a/ext/tk/lib/tkextlib/bwidget/panedwindow.rb +++ b/ext/tk/lib/tkextlib/bwidget/panedwindow.rb @@ -25,7 +25,13 @@ class Tk::BWidget::PanedWindow def get_frame(idx, &b) win = window(tk_send_without_enc('getframe', idx)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end end diff --git a/ext/tk/lib/tkextlib/bwidget/panelframe.rb b/ext/tk/lib/tkextlib/bwidget/panelframe.rb index 13f8817d7..84bae0768 100644 --- a/ext/tk/lib/tkextlib/bwidget/panelframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/panelframe.rb @@ -36,7 +36,13 @@ class Tk::BWidget::PanelFrame def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/progressdlg.rb b/ext/tk/lib/tkextlib/bwidget/progressdlg.rb index fbf00f3b0..32600255d 100644 --- a/ext/tk/lib/tkextlib/bwidget/progressdlg.rb +++ b/ext/tk/lib/tkextlib/bwidget/progressdlg.rb @@ -51,4 +51,8 @@ class Tk::BWidget::ProgressDlg def value= (val) @keys['variable'].value = val end + + def create + window(tk_call(self.class::TkCommandNames[0], @path, *hash_kv(@keys))) + end end diff --git a/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb b/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb index a3986681a..010c960ec 100644 --- a/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb @@ -23,7 +23,13 @@ class Tk::BWidget::ScrollableFrame def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb b/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb index e9e53235b..3599fd845 100644 --- a/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb +++ b/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb @@ -21,7 +21,13 @@ class Tk::BWidget::ScrolledWindow def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/selectcolor.rb b/ext/tk/lib/tkextlib/bwidget/selectcolor.rb index 742a84cd8..0f9014f8d 100644 --- a/ext/tk/lib/tkextlib/bwidget/selectcolor.rb +++ b/ext/tk/lib/tkextlib/bwidget/selectcolor.rb @@ -10,6 +10,11 @@ require 'tkextlib/bwidget/messagedlg' module Tk module BWidget class SelectColor < Tk::BWidget::MessageDlg + class Dialog < Tk::BWidget::SelectColor + end + class Menubutton < Tk::Menubutton + end + MenuButton = Menubutton end end end @@ -43,3 +48,26 @@ class Tk::BWidget::SelectColor tk_call('SelectColor::setcolor', idx, color) end end + +class Tk::BWidget::SelectColor::Dialog + def create_self(keys) + super(keys) + @keys['type'] = 'dialog' + end + + def create + @keys['type'] = 'dialog' # 'dialog' type returns color + tk_call(Tk::BWidget::SelectColor::TkCommandNames[0], + @path, *hash_kv(@keys)) + end +end + +class Tk::BWidget::SelectColor::Menubutton + def create_self(keys) + keys = {} unless keys + keys = _symbolkey2str(keys) + keys['type'] = 'menubutton' # 'toolbar' type returns widget path + window(tk_call(Tk::BWidget::SelectColor::TkCommandNames[0], + @path, *hash_kv(keys))) + end +end diff --git a/ext/tk/lib/tkextlib/bwidget/selectfont.rb b/ext/tk/lib/tkextlib/bwidget/selectfont.rb index 478787602..e53eb3b5b 100644 --- a/ext/tk/lib/tkextlib/bwidget/selectfont.rb +++ b/ext/tk/lib/tkextlib/bwidget/selectfont.rb @@ -66,7 +66,7 @@ class Tk::BWidget::SelectFont::Dialog end def create - @keys['type'] = 'dialog' + @keys['type'] = 'dialog' # 'dialog' type returns font name tk_call(Tk::BWidget::SelectFont::TkCommandNames[0], @path, *hash_kv(@keys)) end end @@ -79,7 +79,8 @@ class Tk::BWidget::SelectFont::Toolbar def create_self(keys) keys = {} unless keys keys = _symbolkey2str(keys) - keys['type'] = 'toolbar' - tk_call(Tk::BWidget::SelectFont::TkCommandNames[0], @path, *hash_kv(keys)) + keys['type'] = 'toolbar' # 'toolbar' type returns widget path + window(tk_call(Tk::BWidget::SelectFont::TkCommandNames[0], + @path, *hash_kv(keys))) end end diff --git a/ext/tk/lib/tkextlib/bwidget/statusbar.rb b/ext/tk/lib/tkextlib/bwidget/statusbar.rb index df16e4c0b..39c678d37 100644 --- a/ext/tk/lib/tkextlib/bwidget/statusbar.rb +++ b/ext/tk/lib/tkextlib/bwidget/statusbar.rb @@ -36,7 +36,13 @@ class Tk::BWidget::StatusBar def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/titleframe.rb b/ext/tk/lib/tkextlib/bwidget/titleframe.rb index f51949043..68534e66e 100644 --- a/ext/tk/lib/tkextlib/bwidget/titleframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/titleframe.rb @@ -21,7 +21,13 @@ class Tk::BWidget::TitleFrame def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end end diff --git a/ext/tk/lib/tkextlib/bwidget/tree.rb b/ext/tk/lib/tkextlib/bwidget/tree.rb index e7178debe..7a46db575 100644 --- a/ext/tk/lib/tkextlib/bwidget/tree.rb +++ b/ext/tk/lib/tkextlib/bwidget/tree.rb @@ -263,14 +263,26 @@ class Tk::BWidget::Tree::Node include TkTreatTagFont TreeNode_TBL = TkCore::INTERP.create_table - TreeNode_ID = ['bw:node'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TreeNode_TBL.clear } + (TreeNode_ID = ['bw:node'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + TreeNode_TBL.mutex.synchronize{ TreeNode_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless TreeNode_TBL[tpath] - TreeNode_TBL[tpath][id]? TreeNode_TBL[tpath][id]: id + TreeNode_TBL.mutex.synchronize{ + if TreeNode_TBL[tpath] + TreeNode_TBL[tpath][id]? TreeNode_TBL[tpath][id]: id + else + id + end + } end def initialize(tree, *args) @@ -311,13 +323,17 @@ class Tk::BWidget::Tree::Node if keys.key?('nodename') @path = @id = keys.delete('nodename') else - @path = @id = TreeNode_ID.join(TkCore::INTERP._ip_id_) - TreeNode_ID[1].succ! + TreeNode_ID.mutex.synchronize{ + @path = @id = TreeNode_ID.join(TkCore::INTERP._ip_id_) + TreeNode_ID[1].succ! + } end - TreeNode_TBL[@id] = self - TreeNode_TBL[@tpath] = {} unless TreeNode_TBL[@tpath] - TreeNode_TBL[@tpath][@id] = self + TreeNode_TBL.mutex.synchronize{ + TreeNode_TBL[@id] = self + TreeNode_TBL[@tpath] = {} unless TreeNode_TBL[@tpath] + TreeNode_TBL[@tpath][@id] = self + } @tree.insert(index, parent, @id, keys) end diff --git a/ext/tk/lib/tkextlib/bwidget/widget.rb b/ext/tk/lib/tkextlib/bwidget/widget.rb index 568e503a8..34e51308a 100644 --- a/ext/tk/lib/tkextlib/bwidget/widget.rb +++ b/ext/tk/lib/tkextlib/bwidget/widget.rb @@ -43,7 +43,13 @@ module Tk::BWidget::Widget def self.create(klass, path, rename=None, &b) win = window(tk_call('Widget::create', klass, path, rename)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/itcl/incr_tcl.rb b/ext/tk/lib/tkextlib/itcl/incr_tcl.rb index 07abf3a7b..2b75d62eb 100644 --- a/ext/tk/lib/tkextlib/itcl/incr_tcl.rb +++ b/ext/tk/lib/tkextlib/itcl/incr_tcl.rb @@ -40,16 +40,22 @@ module Tk class ItclObject < TkObject ITCL_CLASSNAME = ''.freeze - ITCL_OBJ_ID = ['itclobj'.freeze, '00000'.taint].freeze + (ITCL_OBJ_ID = ['itclobj'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } ITCL_OBJ_TBL = {}.taint def initialize(*args) if (@klass = self.class::ITCL_CLASSNAME).empty? fail RuntimeError, 'unknown itcl class (abstract class?)' end - @id = Tk::Itcl::ItclObject::TCL_OBJ_ID.join(TkCore::INTERP._ip_id_) + Tk::Itcl::ItclObject::ITCL_OBJ_ID.mutex.synchronize{ + @id = Tk::Itcl::ItclObject::TCL_OBJ_ID.join(TkCore::INTERP._ip_id_) + Tk::Itcl::ItclObject::ITCL_OBJ_ID[1].succ! + } @path = @id - Tk::Itcl::ItclObject::ITCL_OBJ_ID[1].succ! end def self.call_proc(name, *args) diff --git a/ext/tk/lib/tkextlib/itk/incr_tk.rb b/ext/tk/lib/tkextlib/itk/incr_tk.rb index c7b4e40af..e06deb552 100644 --- a/ext/tk/lib/tkextlib/itk/incr_tk.rb +++ b/ext/tk/lib/tkextlib/itk/incr_tk.rb @@ -145,9 +145,16 @@ module Tk private :__config_cmd ComponentID_TBL = TkCore::INTERP.create_table - Itk_Component_ID = ['itk:component'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ ComponentID_TBL.clear } + (Itk_Component_ID = ['itk:component'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + ComponentID_TBL.mutex.synchronize{ ComponentID_TBL.clear } + } def self.id2obj(master, id) if master.kind_of?(TkObject) @@ -155,8 +162,13 @@ module Tk else master = master.to_s end - return id unless ComponentID_TBL.key?(master) - (ComponentID_TBL[master].key?(id))? ComponentID_TBL[master][id]: id + ComponentID_TBL.mutex.synchronize{ + if ComponentID_TBL.key?(master) + (ComponentID_TBL[master].key?(id))? ComponentID_TBL[master][id]: id + else + id + end + } end def self.new(master, component=nil) @@ -171,17 +183,21 @@ module Tk elsif component component = component.to_s else - component = Itk_Component_ID.join(TkCore::INTERP._ip_id_) - Itk_Component_ID[1].succ! + Itk_Component_ID.mutex.synchronize{ + component = Itk_Component_ID.join(TkCore::INTERP._ip_id_) + Itk_Component_ID[1].succ! + } end - if ComponentID_TBL.key?(master) - if ComponentID_TBL[master].key?(component) - return ComponentID_TBL[master][component] + ComponentID_TBL.mutex.synchronize{ + if ComponentID_TBL.key?(master) + if ComponentID_TBL[master].key?(component) + return ComponentID_TBL[master][component] + end + else + ComponentID_TBL[master] = {} end - else - ComponentID_TBL[master] = {} - end + } super(master, component) end @@ -190,7 +206,9 @@ module Tk @master = master @component = component - ComponentID_TBL[@master][@component] = self + ComponentID_TBL.mutex.synchronize{ + ComponentID_TBL[@master][@component] = self + } begin @widget = window(tk_call(@master, 'component', @component)) diff --git a/ext/tk/lib/tkextlib/iwidgets/calendar.rb b/ext/tk/lib/tkextlib/iwidgets/calendar.rb index 0152f8593..236ca96f0 100644 --- a/ext/tk/lib/tkextlib/iwidgets/calendar.rb +++ b/ext/tk/lib/tkextlib/iwidgets/calendar.rb @@ -45,6 +45,23 @@ class Tk::Iwidgets::Calendar class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [?d, ?s, :date], nil ] PROC_TBL = [ [?s, TkComm.method(:string) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) diff --git a/ext/tk/lib/tkextlib/iwidgets/entryfield.rb b/ext/tk/lib/tkextlib/iwidgets/entryfield.rb index 6aa933ce0..1f9effb46 100644 --- a/ext/tk/lib/tkextlib/iwidgets/entryfield.rb +++ b/ext/tk/lib/tkextlib/iwidgets/entryfield.rb @@ -42,6 +42,23 @@ class Tk::Iwidgets::Entryfield [ ?w, TkComm.method(:window) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); end diff --git a/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb b/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb index 028f6ac0e..4e7d8f857 100644 --- a/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb +++ b/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb @@ -30,6 +30,23 @@ class Tk::Iwidgets::Hierarchy class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [?n, ?s, :node], nil ] PROC_TBL = [ [?s, TkComm.method(:string) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -57,6 +74,22 @@ class Tk::Iwidgets::Hierarchy nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -78,6 +111,23 @@ class Tk::Iwidgets::Hierarchy nil ] PROC_TBL = [ [ ?s, TkComm.method(:string) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) diff --git a/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb b/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb index 407c8f2aa..b07602e34 100644 --- a/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb +++ b/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb @@ -171,10 +171,16 @@ class Tk::Iwidgets::Scrolledcanvas end def delete(*args) - if TkcItem::CItemID_TBL[self.path] + tbl = nil + TkcItem::CItemID_TBL.mutex.synchronize{ + tbl = TkcItem::CItemID_TBL[self.path] + } + if tbl find('withtag', *args).each{|item| if item.kind_of?(TkcItem) - TkcItem::CItemID_TBL[self.path].delete(item.id) + TkcItem::CItemID_TBL.mutex.synchronize{ + tbl.delete(item.id) + } end } end diff --git a/ext/tk/lib/tkextlib/iwidgets/spinner.rb b/ext/tk/lib/tkextlib/iwidgets/spinner.rb index 174b9bd50..126cfe7c9 100644 --- a/ext/tk/lib/tkextlib/iwidgets/spinner.rb +++ b/ext/tk/lib/tkextlib/iwidgets/spinner.rb @@ -37,6 +37,23 @@ class Tk::Iwidgets::Spinner [ ?w, TkComm.method(:window) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); end diff --git a/ext/tk/lib/tkextlib/tcllib/ico.rb b/ext/tk/lib/tkextlib/tcllib/ico.rb index 3beeb11a4..8c92926a4 100644 --- a/ext/tk/lib/tkextlib/tcllib/ico.rb +++ b/ext/tk/lib/tkextlib/tcllib/ico.rb @@ -94,8 +94,10 @@ class Tk::Tcllib::ICO if keys.key?('name') @path = keys['name'].to_s else - @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_) - Tk_Image_ID[1].succ! + Tk_Image_ID.mutex.synchronize{ + @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_) + Tk_Image_ID[1].succ! + } end tk_call_without_enc('::ico::getIcon', file, index, '-name', @path, '-format', 'image', *hash_kv(keys, true)) diff --git a/ext/tk/lib/tkextlib/tcllib/plotchart.rb b/ext/tk/lib/tkextlib/tcllib/plotchart.rb index cde42c8a0..06ab20f3e 100644 --- a/ext/tk/lib/tkextlib/tcllib/plotchart.rb +++ b/ext/tk/lib/tkextlib/tcllib/plotchart.rb @@ -265,7 +265,9 @@ module Tk::Tcllib::Plotchart private :_create_chart def __destroy_hook__ - Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{ + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + } end def plot(series, x, y) @@ -374,7 +376,9 @@ module Tk::Tcllib::Plotchart private :_create_chart def __destroy_hook__ - Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{ + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + } end def plot(series, radius, angle) @@ -645,7 +649,9 @@ module Tk::Tcllib::Plotchart private :_create_chart def __destroy_hook__ - Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{ + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + } end def plot(series, dat, col=None) @@ -834,23 +840,38 @@ module Tk::Tcllib::Plotchart ############################ class PlotSeries < TkObject SeriesID_TBL = TkCore::INTERP.create_table - Series_ID = ['series'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ SeriesID_TBL.clear } + + (Series_ID = ['series'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + TkCore::INTERP.init_ip_env{ + SeriesID_TBL.mutex.synchronize{ SeriesID_TBL.clear } + } def self.id2obj(chart, id) path = chart.path - return id unless SeriesID_TBL[path] - SeriesID_TBL[path][id]? SeriesID_TBL[path][id]: id + SeriesID_TBL.mutex.synchronize{ + if SeriesID_TBL[path] + SeriesID_TBL[path][id]? SeriesID_TBL[path][id]: id + else + id + end + } end def initialize(chart, keys=nil) @parent = @chart_obj = chart @ppath = @chart_obj.path - @path = @series = @id = Series_ID.join(TkCore::INTERP._ip_id_) - # SeriesID_TBL[@id] = self - SeriesID_TBL[@ppath] = {} unless SeriesID_TBL[@ppath] - SeriesID_TBL[@ppath][@id] = self - Series_ID[1].succ! + Series_ID.mutex.synchronize{ + @path = @series = @id = Series_ID.join(TkCore::INTERP._ip_id_) + Series_ID[1].succ! + } + SeriesID_TBL.mutex.synchronize{ + SeriesID_TBL[@ppath] ||= {} + SeriesID_TBL[@ppath][@id] = self + } dataconfig(keys) if keys.kind_of?(Hash) end diff --git a/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb b/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb index 92dde65ce..b366e0198 100644 --- a/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb +++ b/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb @@ -125,7 +125,9 @@ module Tk::Tcllib::Tkpiechart def delete tk_call_without_enc('::stooop::delete', @tag_key) - CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + CItemID_TBL.mutex.synchronize{ + CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + } self end @@ -184,8 +186,10 @@ module Tk::Tcllib::Tkpiechart @id = "slices(#{@tag_key})" @tag = TkcNamedTag.new(@pie.canvas, @id) - CItemID_TBL[@path] = {} unless CItemID_TBL[@path] - CItemID_TBL[@path][@id] = self + CItemID_TBL.mutex.synchronize{ + CItemID_TBL[@path] = {} unless CItemID_TBL[@path] + CItemID_TBL[@path][@id] = self + } end def tag_key @@ -200,7 +204,9 @@ module Tk::Tcllib::Tkpiechart def delete tk_call_without_enc('pie::deleteSlice', @pie.tag_key, @tag_key) - CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + CItemID_TBL.mutex.synchronize{ + CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + } @pie._delete_slice(self) self end diff --git a/ext/tk/lib/tkextlib/tile.rb b/ext/tk/lib/tkextlib/tile.rb index b527935a6..02473d57a 100644 --- a/ext/tk/lib/tkextlib/tile.rb +++ b/ext/tk/lib/tkextlib/tile.rb @@ -18,11 +18,8 @@ require 'tkextlib/tile/setup.rb' # TkPackage.require('tile', '0.7') if Tk::TK_MAJOR_VERSION > 8 || (Tk::TK_MAJOR_VERSION == 8 && Tk::TK_MINOR_VERSION >= 5) - begin - verstr = TkPackage.require('Ttk') - rescue RuntimeError - verstr = TkPackage.require('tile') - end + TkPackage.require('tile') # for compatibility (version check of 'tile') + verstr = TkPackage.require('Ttk') else verstr = TkPackage.require('tile') end @@ -101,16 +98,97 @@ module Tk end def self.__Import_Tile_Widgets__! + warn 'Warning: "Tk::Tile::__Import_Tile_Widgets__!" is obsolete.' << + ' To control default widget set, use "Tk.default_widget_set = :Ttk"' Tk.tk_call('namespace', 'import', '-force', 'ttk::*') end - def self.load_images(imgdir, pat=TkComm::None) - images = Hash[*TkComm.simplelist(Tk.tk_call('::tile::LoadImages', - imgdir, pat))] - images.keys.each{|k| - images[k] = TkPhotoImage.new(:imagename=>images[k], - :without_creating=>true) + def self.__define_LoadImages_proc_for_compatibility__! + # Ttk 8.5 (Tile 0.8) lost 'LoadImages' utility procedure. + # So, some old scripts doen't work, because those scripts use the + # procedure to define local styles. + # Of course, rewriting such Tcl/Tk scripts isn't difficult for + # Tcl/Tk users. However, it may be troublesome for Ruby/Tk users + # who use such Tcl/Tk scripts as it is. + # This method may help Ruby/Tk users who don't want to modify old + # Tcl/Tk scripts for the latest version of Ttk (Tile) extension. + # This method defines a comaptible 'LoadImages' procedure on the + # Tcl/Tk interpreter working under Ruby/Tk. + # Please give attention to use this method. It may conflict with + # some definitions on Tcl/Tk scripts. + klass_name = self.name + proc_name = 'LoadImages' + if Tk::Tile::USE_TTK_NAMESPACE + ns_list = ['::tile'] + if Tk.info(:commands, "::ttk::#{proc_name}").empty? + ns_list << '::ttk' + end + else # Tk::Tile::USE_TILE_NAMESPACE + ns_list = ['::ttk'] + if Tk.info(:commands, "::tile::#{proc_name}").empty? + ns_list << '::tile' + end + end + + ns_list.each{|ns| + cmd = "#{ns}::#{proc_name}" + unless Tk.info(:commands, cmd).empty? + fail RuntimeError, "can't define '#{cmd}' command (already exist)" + end + TkNamespace.eval(ns){ + TkCore::INTERP.add_tk_procs(proc_name, 'imgdir {patterns {*.gif}}', + <<-'EOS') + foreach pattern $patterns { + foreach file [glob -directory $imgdir $pattern] { + set img [file tail [file rootname $file]] + if {![info exists images($img)]} { + set images($img) [image create photo -file $file] + } + } + } + return [array get images] + EOS + } } + end + + def self.load_images(imgdir, pat=nil) + if Tk::Tile::TILE_SPEC_VERSION_ID < 8 + if Tk::Tile::USE_TTK_NAMESPACE + cmd = '::ttk::LoadImages' + else # Tk::Tile::USE_TILE_NAMESPACE + cmd = '::tile::LoadImages' + end + pat ||= TkComm::None + images = Hash[*TkComm.simplelist(Tk.tk_call(cmd, imgdir, pat))] + images.keys.each{|k| + images[k] = TkPhotoImage.new(:imagename=>images[k], + :without_creating=>true) + } + else ## TILE_SPEC_VERSION_ID >= 8 + pat ||= '*.gif' + if pat.kind_of?(Array) + pat_list = pat + else + pat_list = [ pat ] + end + Dir.chdir(imgdir){ + pat_list.each{|pat| + Dir.glob(pat).each{|f| + img = File.basename(f, '.*') + unless TkComm.bool(Tk.info('exists', "images(#{img})")) + Tk.tk_call('set', "images(#{img})", + Tk.tk_call('image', 'create', 'photo', '-file', f)) + end + } + } + } + images = Hash[*TkComm.simplelist(Tk.tk_call('array', 'get', 'images'))] + images.keys.each{|k| + images[k] = TkPhotoImage.new(:imagename=>images[k], + :without_creating=>true) + } + end images end @@ -120,11 +198,20 @@ module Tk end module KeyNav - def self.enableMnemonics(w) - Tk.tk_call('::keynav::enableMnemonics', w) - end - def self.defaultButton(w) - Tk.tk_call('::keynav::defaultButton', w) + if Tk::Tile::TILE_SPEC_VERSION_ID < 8 + def self.enableMnemonics(w) + Tk.tk_call('::keynav::enableMnemonics', w) + end + def self.defaultButton(w) + Tk.tk_call('::keynav::defaultButton', w) + end + else # dummy + def self.enableMnemonics(w) + "" + end + def self.defaultButton(w) + "" + end end end @@ -139,6 +226,12 @@ module Tk Menu = 'TkMenuFont' SmallCaption = 'TkSmallCaptionFont' Icon = 'TkIconFont' + + TkFont::SYSTEM_FONT_NAMES.add [ + 'TkDefaultFont', 'TkTextFont', 'TkHeadingFont', + 'TkCaptionFont', 'TkTooltipFont', 'TkFixedFont', + 'TkMenuFont', 'TkSmallCaptionFont', 'TkIconFont' + ] end module ParseStyleLayout @@ -177,7 +270,7 @@ module Tk end private :__val2ruby_optkeys - def instate(state, script=nil, &b) + def ttk_instate(state, script=nil, &b) if script tk_send('instate', state, script) elsif b @@ -186,19 +279,30 @@ module Tk bool(tk_send('instate', state)) end end + alias tile_instate ttk_instate - def state(state=nil) + def ttk_state(state=nil) if state tk_send('state', state) else list(tk_send('state')) end end + alias tile_state ttk_state - def identify(x, y) + def ttk_identify(x, y) ret = tk_send_without_enc('identify', x, y) (ret.empty?)? nil: ret end + alias tile_identify ttk_identify + + # remove instate/state/identify method + # to avoid the conflict with widget options + if Tk.const_defined?(:USE_OBSOLETE_TILE_STATE_METHOD) && Tk::USE_OBSOLETE_TILE_STATE_METHOD + alias instate ttk_instate + alias state ttk_state + alias identify ttk_identify + end end ###################################### diff --git a/ext/tk/lib/tkextlib/tile/style.rb b/ext/tk/lib/tkextlib/tile/style.rb index e01011cb2..bf8acb34b 100644 --- a/ext/tk/lib/tkextlib/tile/style.rb +++ b/ext/tk/lib/tkextlib/tile/style.rb @@ -19,8 +19,93 @@ end class << Tk::Tile::Style if Tk::Tile::TILE_SPEC_VERSION_ID < 8 TkCommandNames = ['style'.freeze].freeze - else + + # --- Tk::Tile::Style.__define_wrapper_proc_for_compatibility__! --- + # On Ttk (Tile) extension, 'style' command has imcompatible changes + # depend on the version of the extention. It requires modifying the + # Tcl/Tk scripts to define local styles. The rule for modification + # is a simple one. But, if users want to keep compatibility between + # versions of the extension, they will have to contrive to do that. + # It may be troublesome, especially for Ruby/Tk users. + # This method may help such work. This method make some definitions + # on the Tcl/Tk interpreter to work with different version of style + # command format. Please give attention to use this method. It may + # conflict with some definitions on Tcl/Tk scripts. + if Tk::Tile::TILE_SPEC_VERSION_ID < 7 + def __define_wrapper_proc_for_compatibility__! + unless Tk.info(:commands, '::ttk::style').empty? + fail RuntimeError, + "can't define ':ttk::style' command (already exist)" + end + TkCore::INTERP.add_tk_procs('::ttk::style', 'args', <<-'EOS') + if [string equal [lrange $args 0 1] {element create}] { + if [string equal [lindex $args 3] image] { + set spec [lindex $args 4] + set map [lrange $spec 1 end] + if [llength $map] { + # return [eval [concat [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]] + return [uplevel 1 [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]] + } + } + } + # return [eval "::style $args"] + return [uplevel 1 ::style $args] + EOS + ######################### + end + else ### TILE_SPEC_VERSION_ID == 7 + def __define_wrapper_proc_for_compatibility__! + unless Tk.info(:commands, '::ttk::style').empty? + fail RuntimeError, + "can't define ':ttk::style' command (already exist)" + end + TkCore::INTERP.add_tk_procs('::ttk::style', 'args', <<-'EOS') + if [string equal [lrange $args 0 1] {element create}] { + if [string equal [lindex $args 3] image] { + set spec [lindex $args 4] + set map [lrange $spec 1 end] + if [llength $map] { + # return [eval [concat [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]] + return [uplevel 1 [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]] + } + } + } elseif [string equal [lindex $args 0] default] { + # return [eval "::style [lreplace $args 0 0 configure]"] + return [uplevel 1 ::style [lreplace $args 0 0 configure]] + } + # return [eval "::style $args"] + return [uplevel 1 ::style $args] + EOS + ######################### + end + end + else ### TILE_SPEC_VERSION_ID >= 8 TkCommandNames = ['::ttk::style'.freeze].freeze + + def __define_wrapper_proc_for_compatibility__! + unless Tk.info(:commands, '::style').empty? + fail RuntimeError, "can't define '::style' command (already exist)" + end + TkCore::INTERP.add_tk_procs('::style', 'args', <<-'EOS') + if [string equal [lrange $args 0 1] {element create}] { + if [string equal [lindex $args 3] image] { + set name [lindex $args 4] + set opts [lrange $args 5 end] + set idx [lsearch $opts -map] + if {$idx >= 0 && [expr $idx % 2 == 0]} { + # return [eval [concat [list ::ttk::style element create [lindex $args 2] image [concat $name [lindex $opts [expr $idx + 1]]]] [lreplace $opts $idx [expr $idx + 1]]]] + return [uplevel 1 [list ::ttk::style element create [lindex $args 2] image [concat $name [lindex $opts [expr $idx + 1]]]] [lreplace $opts $idx [expr $idx + 1]]] + } + } + } elseif [string equal [lindex $args 0] default] { + # return [eval "::ttk::style [lreplace $args 0 0 configure]"] + return [uplevel 1 ::ttk::style [lreplace $args 0 0 configure]] + } + # return [eval "::ttk::style $args"] + return [uplevel 1 ::ttk::style $args] + EOS + ######################### + end end def configure(style=nil, keys=nil) @@ -98,7 +183,52 @@ class << Tk::Tile::Style end def element_create(name, type, *args) - tk_call(TkCommandNames[0], 'element', 'create', name, type, *args) + if type == 'image' || type == :image + element_create_image(name, *args) + else + tk_call(TkCommandNames[0], 'element', 'create', name, type, *args) + end + end + + def element_create_image(name, *args) + fail ArgumentError, 'Must supply a base image' unless (spec = args.shift) + if (opts = args.shift) + if opts.kind_of?(Hash) + opts = _symbolkey2str(opts) + else + fail ArgumentError, 'bad option' + end + end + fail ArgumentError, 'too many arguments' unless args.empty? + + if spec.kind_of?(Array) + # probably, command format is tile 0.8+ (Tcl/Tk8.5+) style + if Tk::Tile::TILE_SPEC_VERSION_ID >= 8 + if opts + tk_call(TkCommandNames[0], + 'element', 'create', name, 'image', spec, opts) + else + tk_call(TkCommandNames[0], 'element', 'create', name, 'image', spec) + end + else + fail ArgumentError, 'illegal arguments' if opts.key?('map') + base = spec.shift + opts['map'] = spec + tk_call(TkCommandNames[0], + 'element', 'create', name, 'image', base, opts) + end + else + # probably, command format is tile 0.7.8 or older style + if Tk::Tile::TILE_SPEC_VERSION_ID >= 8 + spec = [spec, *(opts.delete('map'))] if opts.key?('map') + end + if opts + tk_call(TkCommandNames[0], + 'element', 'create', name, 'image', spec, opts) + else + tk_call(TkCommandNames[0], 'element', 'create', name, 'image', spec) + end + end end def element_names() diff --git a/ext/tk/lib/tkextlib/tile/treeview.rb b/ext/tk/lib/tkextlib/tile/treeview.rb index 36496ee0b..7f31b9c23 100644 --- a/ext/tk/lib/tkextlib/tile/treeview.rb +++ b/ext/tk/lib/tkextlib/tile/treeview.rb @@ -381,7 +381,7 @@ module Tk::Tile::TreeviewConfig when :item, 'item' ['width'] when :column, 'column' - super(id[1]) + super(id[1]) + ['minwidth'] when :tag, 'tag' super(id[1]) when :heading, 'heading' @@ -413,7 +413,7 @@ module Tk::Tile::TreeviewConfig when :item, 'item' ['open'] when :column, 'column' - super(id[1]) + super(id[1]) + ['stretch'] when :tag, 'tag' super(id[1]) when :heading, 'heading' @@ -617,30 +617,43 @@ end class Tk::Tile::Treeview::Item < TkObject ItemID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ Tk::Tile::Treeview::Item::ItemID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Item::ItemID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::Tile::Treeview::Item::ItemID_TBL[tpath] - (Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id])? \ - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]: id + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] + (Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id])? \ + Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]: id + else + id + end + } end def self.assign(tree, id) tpath = tree.path - if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] && - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] - return Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] - end + obj = nil + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] && + Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] + return Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] + end - obj = self.allocate - obj.instance_eval{ - @parent = @t = tree - @tpath = tpath - @path = @id = id + obj = self.allocate + obj.instance_eval{ + @parent = @t = tree + @tpath = tpath + @path = @id = id + } + Tk::Tile::Treeview::Item::ItemID_TBL[tpath] ||= {} + Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] = obj } - ItemID_TBL[tpath] = {} unless ItemID_TBL[tpath] - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] = obj obj end @@ -669,8 +682,10 @@ class Tk::Tile::Treeview::Item < TkObject @parent = @t = tree @tpath = tree.path @path = @id = _insert_item(@t, parent_item, idx, keys) - ItemID_TBL[@tpath] = {} unless ItemID_TBL[@tpath] - ItemID_TBL[@tpath][@id] = self + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + ItemID_TBL[@tpath] = {} unless ItemID_TBL[@tpath] + ItemID_TBL[@tpath][@id] = self + } end def id @id @@ -804,22 +819,35 @@ end class Tk::Tile::Treeview::Root < Tk::Tile::Treeview::Item def self.new(tree, keys = {}) tpath = tree.path - if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] && - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][''] - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][''] - else - super(tree, keys) - end + obj = nil + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] && + Tk::Tile::Treeview::Item::ItemID_TBL[tpath][''] + obj = Tk::Tile::Treeview::Item::ItemID_TBL[tpath][''] + else + #super(tree, keys) + (obj = self.allocate).instance_eval{ + @parent = @t = tree + @tpath = tree.path + @path = @id = '' + Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] ||= {} + Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self + } + end + } + obj.configure(keys) if keys && ! keys.empty? + obj end def initialize(tree, keys = {}) + # dummy:: not called by 'new' method @parent = @t = tree @tpath = tree.path @path = @id = '' - unless Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] - Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] = {} - end - Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] ||= {} + Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self + } end end @@ -829,24 +857,42 @@ class Tk::Tile::Treeview::Tag < TkObject include TkTreatTagFont TagID_TBL = TkCore::INTERP.create_table - Tag_ID = ['tile_treeview_tag'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ Tk::Tile::Treeview::Tag::TagID_TBL.clear } + (Tag_ID = ['tile_treeview_tag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + Tk::Tile::Treeview::Tag::TagID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Tag::TagID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::Tile::Treeview::Tag::TagID_TBL[tpath] - (Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id])? \ - Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id]: id + Tk::Tile::Treeview::Tag::TagID_TBL.mutex.synchronize{ + if Tk::Tile::Treeview::Tag::TagID_TBL[tpath] + (Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id])? \ + Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id]: id + else + id + end + } end def initialize(tree, keys=nil) @parent = @t = tree @tpath = tree.path - @path = @id = Tag_ID.join(TkCore::INTERP._ip_id_) - TagID_TBL[@tpath] = {} unless TagID_TBL[@tpath] - TagID_TBL[@tpath][@id] = self - Tag_ID[1].succ! + Tag_ID.mutex.synchronize{ + @path = @id = Tag_ID.join(TkCore::INTERP._ip_id_) + Tag_ID[1].succ! + } + TagID_TBL.mutex.synchronize{ + TagID_TBL[@tpath] = {} unless TagID_TBL[@tpath] + TagID_TBL[@tpath][@id] = self + } if keys && keys != None tk_call_without_enc(@tpath, 'tag', 'configure', *hash_kv(keys, true)) end @@ -919,8 +965,12 @@ class Tk::Tile::Treeview < TkWindow WidgetClassNames[WidgetClassName] = self def __destroy_hook__ - Tk::Tile::Treeview::Item::ItemID_TBL.delete(@path) - Tk::Tile::Treeview::Tag::ItemID_TBL.delete(@path) + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Item::ItemID_TBL.delete(@path) + } + Tk::Tile::Treeview::Tag::ItemID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Tag::ItemID_TBL.delete(@path) + } end def self.style(*args) diff --git a/ext/tk/lib/tkextlib/tkDND/tkdnd.rb b/ext/tk/lib/tkextlib/tkDND/tkdnd.rb index a040532eb..ea91d3d1f 100644 --- a/ext/tk/lib/tkextlib/tkDND/tkdnd.rb +++ b/ext/tk/lib/tkextlib/tkDND/tkdnd.rb @@ -57,6 +57,22 @@ module Tk nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + # setup tables _setup_subst_table(KEY_TBL, PROC_TBL); end diff --git a/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb b/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb index 8527f61df..d893a83cf 100644 --- a/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb +++ b/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb @@ -39,7 +39,10 @@ class Tk::HTML_Widget::ClippingWindow WidgetClassNames[WidgetClassName] = self HtmlClip_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ HtmlClip_TBL.clear } + + TkCore::INTERP.init_ip_env{ + HtmlClip_TBL.mutex.synchronize{ HtmlClip_TBL.clear } + } def self.new(parent, keys={}) if parent.kind_of?(Hash) @@ -54,7 +57,9 @@ class Tk::HTML_Widget::ClippingWindow else ppath = '' end - return HtmlClip_TBL[ppath] if HtmlClip_TBL[ppath] + HtmlClip_TBL.mutex.synchronize{ + return HtmlClip_TBL[ppath] if HtmlClip_TBL[ppath] + } widgetname = keys.delete('widgetname') if widgetname =~ /^(.*)\.[^.]+$/ @@ -62,7 +67,9 @@ class Tk::HTML_Widget::ClippingWindow if ppath2[0] != ?. ppath2 = ppath + '.' + ppath2 end - return HtmlClip_TBL[ppath2] if HtmlClip_TBL[ppath2] + HtmlClip_TBL.mutex.synchronize{ + return HtmlClip_TBL[ppath2] if HtmlClip_TBL[ppath2] + } ppath = ppath2 end @@ -79,7 +86,9 @@ class Tk::HTML_Widget::ClippingWindow @parent = parent @ppath = parent.path @path = @id = @ppath + '.x' - HtmlClip_TBL[@ppath] = self + HtmlClip_TBL.mutex.synchronize{ + HtmlClip_TBL[@ppath] = self + } end def method_missing(m, *args, &b) diff --git a/ext/tk/lib/tkextlib/tktable/tktable.rb b/ext/tk/lib/tkextlib/tktable/tktable.rb index 4edaabc84..fb8a8b0f7 100644 --- a/ext/tk/lib/tkextlib/tktable/tktable.rb +++ b/ext/tk/lib/tkextlib/tktable/tktable.rb @@ -118,23 +118,39 @@ class Tk::TkTable::CellTag include TkTreatTagFont CellTagID_TBL = TkCore::INTERP.create_table - CellTag_ID = ['tktbl:celltag'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ CellTagID_TBL.clear } + (CellTag_ID = ['tktbl:celltag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + CellTagID_TBL.mutex.synchronize{ CellTagID_TBL.clear } + } def self.id2obj(table, id) tpath = table.path - return id unless CellTagID_TBL[tpath] - CellTagID_TBL[tpath][id]? CellTagID_TBL[tpath][id] : id + CellTagID_TBL.mutex.synchronize{ + if CellTagID_TBL[tpath] + CellTagID_TBL[tpath][id]? CellTagID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, keys=nil) @parent = @t = parent @tpath - parent.path - @path = @id = CellTag_ID.join(TkCore::INTERP._ip_id_) - CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] - CellTagID_TBL[@tpath][@id] = self - CellTag_ID[1].succ! + CellTag_ID.mutex.synchronize{ + @path = @id = CellTag_ID.join(TkCore::INTERP._ip_id_) + CellTag_ID[1].succ! + } + CellTagID_TBL.mutex.synchronize{ + CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] + CellTagID_TBL[@tpath][@id] = self + } configure(keys) if keys end @@ -144,7 +160,9 @@ class Tk::TkTable::CellTag def destroy tk_call(@tpath, 'tag', 'delete', @id) - CellTagID_TBL[@tpath].delete(@id) if CellTagID_TBL[@tpath] + CellTagID_TBL.mutex.synchronize{ + CellTagID_TBL[@tpath].delete(@id) if CellTagID_TBL[@tpath] + } self end alias delete destroy @@ -189,22 +207,35 @@ end class Tk::TkTable::NamedCellTag < Tk::TkTable::CellTag def self.new(parent, name, keys=nil) - if CellTagID_TBL[parent.path] && CellTagID_TBL[parent.path][name] - cell = CellTagID_TBL[parent.path][name] - cell.configure(keys) if keys - return cell - else - super(parent, name, keys) - end + obj = nil + CellTagID_TBL.mutex.synchronize{ + if CellTagID_TBL[parent.path] && CellTagID_TBL[parent.path][name] + obj = CellTagID_TBL[parent.path][name] + else + #super(parent, name, keys) + (obj = self.allocate).instance_eval{ + @parent = @t = parent + @tpath = parent.path + @path = @id = name + CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] + CellTagID_TBL[@tpath][@id] = self + } + end + } + obj.configure(keys) if keys && ! keys.empty? + obj end def initialize(parent, name, keys=nil) + # dummy:: not called by 'new' method @parent = @t = parent - @tpath - parent.path + @tpath = parent.path @path = @id = name - CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] - CellTagID_TBL[@tpath][@id] = self - configure(keys) if keys + CellTagID_TBL.mutex.synchronize{ + CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] + CellTagID_TBL[@tpath][@id] = self + } + configure(keys) if keys && ! keys.empty? end end @@ -220,7 +251,9 @@ class Tk::TkTable include Tk::ValidateConfigure def __destroy_hook__ - Tk::TkTable::CelTag::CellTagID_TBL.delete(@path) + Tk::TkTable::CelTag::CellTagID_TBL.mutex.synchronize{ + Tk::TkTable::CelTag::CellTagID_TBL.delete(@path) + } end def __boolval_optkeys @@ -258,6 +291,22 @@ class Tk::TkTable nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -291,6 +340,22 @@ class Tk::TkTable nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -322,6 +387,22 @@ class Tk::TkTable nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -356,6 +437,22 @@ class Tk::TkTable nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); end @@ -746,15 +843,17 @@ class Tk::TkTable end def tagid2obj(tagid) - if Tk::TkTable::CellTag::CellTagID_TBL.key?(@path) - if Tk::TkTable::CellTag::CellTagID_TBL[@path].key?(tagid) - Tk::TkTable::CellTag::CellTagID_TBL[@path][tagid] + Tk::TkTable::CellTag::CellTagID_TBL.mutex.synchronize{ + if Tk::TkTable::CellTag::CellTagID_TBL.key?(@path) + if Tk::TkTable::CellTag::CellTagID_TBL[@path].key?(tagid) + Tk::TkTable::CellTag::CellTagID_TBL[@path][tagid] + else + tagid + end else tagid end - else - tagid - end + } end def tag_cell(tag, *cells) @@ -775,13 +874,15 @@ class Tk::TkTable end def tag_delete(tag) tk_send('tag', 'delete', tagid(tag)) - if Tk::TkTable::CellTag::CellTagID_TBL[@path] - if tag.kind_of? Tk::TkTable::CellTag - Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag.id) - else - Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag) + Tk::TkTable::CellTag::CellTagID_TBL.mutex.synchronize{ + if Tk::TkTable::CellTag::CellTagID_TBL[@path] + if tag.kind_of? Tk::TkTable::CellTag + Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag.id) + else + Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag) + end end - end + } self end def tag_exist?(tag) diff --git a/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb b/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb index 12f7cffab..b72b157dc 100644 --- a/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb +++ b/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb @@ -137,6 +137,22 @@ class Tk::TreeCtrl::NotifyEvent nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + # setup tables to be used by scan_args, _get_subst_key, _get_all_subst_keys # # _get_subst_key() and _get_all_subst_keys() generates key-string @@ -544,10 +560,18 @@ class Tk::TreeCtrl ######################### def __destroy_hook__ - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.delete(@path) - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.delete(@path) - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.delete(@path) - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.delete(@path) + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.delete(@path) + } + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.delete(@path) + } + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.delete(@path) + } + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.delete(@path) + } end ######################### @@ -638,9 +662,11 @@ class Tk::TreeCtrl end def column_delete(idx) - if Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path] - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path].delete(idx) - end + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path] + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path].delete(idx) + end + } tk_send('column', 'delete', idx) self end @@ -750,11 +776,13 @@ class Tk::TreeCtrl end def element_delete(*elems) - if Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path] - elems.each{|elem| - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path].delete(elem) - } - end + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path] + elems.each{|elem| + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path].delete(elem) + } + end + } tk_send('element', 'delete', *elems) self end @@ -885,22 +913,25 @@ class Tk::TreeCtrl def _erase_children(item) item_children(item).each{|i| _erase_children(i)} + # table is already locked Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path].delete(item) end private :_erase_children def item_delete(first, last=None) - if Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path] - if first == 'all' || first == :all || last == 'all' || last == :all - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path].clear - elsif last == None - _erase_children(first) - else - self.range(first, last).each{|id| - _erase_children(id) - } + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path] + if first == 'all' || first == :all || last == 'all' || last == :all + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path].clear + elsif last == None + _erase_children(first) + else + self.range(first, last).each{|id| + _erase_children(id) + } + end end - end + } tk_send('item', 'delete', first, last) self end @@ -1520,11 +1551,13 @@ class Tk::TreeCtrl end def style_delete(*args) - if Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path] - args.each{|sty| - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path].delete(sty) - } - end + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path] + args.each{|sty| + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path].delete(sty) + } + end + } tk_send('style', 'delete', *args) self end @@ -1608,15 +1641,29 @@ end class Tk::TreeCtrl::Column < TkObject TreeCtrlColumnID_TBL = TkCore::INTERP.create_table - TreeCtrlColumnID = ['treectrl_column'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.clear} + (TreeCtrlColumnID = ['treectrl_column'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath] - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id]? \ - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id] : id + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath] + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id]? \ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, keys={}) @@ -1625,17 +1672,19 @@ class Tk::TreeCtrl::Column < TkObject keys = _symbolkey2str(keys) - @path = @id = - keys.delete('tag') || - Tk::TreeCtrl::Column::TreeCtrlColumnID.join(TkCore::INTERP._ip_id_) + Tk::TreeCtrl::Column::TreeCtrlColumnID.mutex.synchronize{ + @path = @id = + keys.delete('tag') || + Tk::TreeCtrl::Column::TreeCtrlColumnID.join(TkCore::INTERP._ip_id_) + Tk::TreeCtrl::Column::TreeCtrlColumnID[1].succ! + } keys['tag'] = @id - unless Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath] - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath] = {} - end - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath][@id] = self - Tk::TreeCtrl::Column::TreeCtrlColumnID[1].succ! + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath] ||= {} + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath][@id] = self + } @tree.column_create(keys) end @@ -1692,11 +1741,18 @@ end class Tk::TreeCtrl::Element < TkObject TreeCtrlElementID_TBL = TkCore::INTERP.create_table - TreeCtrlElementID = ['treectrl_element'.freeze, '00000'.taint].freeze + + (TreeCtrlElementID = ['treectrl_element'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } TreeCtrlElemTypeToClass = {} TkCore::INTERP.init_ip_env{ - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.clear + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.clear + } } def self.type2class(type) @@ -1705,22 +1761,30 @@ class Tk::TreeCtrl::Element < TkObject def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath] - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath][id]? \ + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath] + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath][id]? \ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, type, keys=nil) @tree = parent @tpath = parent.path @type = type.to_s - @path = @id = - Tk::TreeCtrl::Element::TreeCtrlElementID.join(TkCore::INTERP._ip_id_) - unless Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath] - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath] = {} - end - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath][@id] = self - Tk::TreeCtrl::Element::TreeCtrlElementID[1].succ! + Tk::TreeCtrl::Element::TreeCtrlElementID.mutex.synchronize{ + @path = @id = + Tk::TreeCtrl::Element::TreeCtrlElementID.join(TkCore::INTERP._ip_id_) + Tk::TreeCtrl::Element::TreeCtrlElementID[1].succ! + } + + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath] ||= {} + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath][@id] = self + } @tree.element_create(@id, @type, keys) end @@ -1800,13 +1864,22 @@ end class Tk::TreeCtrl::Item < TkObject TreeCtrlItemID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.clear} + TkCore::INTERP.init_ip_env{ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath] - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id]? \ - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id] : id + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath] + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id]? \ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, keys={}) @@ -1814,10 +1887,10 @@ class Tk::TreeCtrl::Item < TkObject @tpath = parent.path @path = @id = @tree.item_create(keys) - unless Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath] - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath] = {} - end - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath][@id] = self + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath] ||= {} + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath][@id] = self + } end def id @@ -2088,27 +2161,45 @@ end class Tk::TreeCtrl::Style < TkObject TreeCtrlStyleID_TBL = TkCore::INTERP.create_table - TreeCtrlStyleID = ['treectrl_style'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.clear } + (TreeCtrlStyleID = ['treectrl_style'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath] - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id]? \ - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id] : id + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath] + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id]? \ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, keys=nil) @tree = parent @tpath = parent.path - @path = @id = - Tk::TreeCtrl::Style::TreeCtrlStyleID.join(TkCore::INTERP._ip_id_) - unless Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath] - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath] = {} - end - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath][@id] = self - Tk::TreeCtrl::Style::TreeCtrlStyleID[1].succ! + + Tk::TreeCtrl::Style::TreeCtrlStyleID.mutex.synchronize{ + @path = @id = + Tk::TreeCtrl::Style::TreeCtrlStyleID.join(TkCore::INTERP._ip_id_) + Tk::TreeCtrl::Style::TreeCtrlStyleID[1].succ! + } + + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath] ||= {} + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath][@id] = self + } @tree.style_create(@id, keys) end diff --git a/ext/tk/lib/tkextlib/version.rb b/ext/tk/lib/tkextlib/version.rb index c7816fd4a..3542c79db 100644 --- a/ext/tk/lib/tkextlib/version.rb +++ b/ext/tk/lib/tkextlib/version.rb @@ -2,5 +2,5 @@ # release date of tkextlib # module Tk - Tkextlib_RELEASE_DATE = '2007-05-26'.freeze + Tkextlib_RELEASE_DATE = '2008-03-29'.freeze end diff --git a/ext/tk/lib/tkextlib/vu/pie.rb b/ext/tk/lib/tkextlib/vu/pie.rb index 78f3fa54d..1975803db 100644 --- a/ext/tk/lib/tkextlib/vu/pie.rb +++ b/ext/tk/lib/tkextlib/vu/pie.rb @@ -116,13 +116,26 @@ end class Tk::Vu::PieSlice SliceID_TBL = TkCore::INTERP.create_table - Pie_Slice_ID = ['vu:pie'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ SliceID_TBL.clear } + + (Pie_Slice_ID = ['vu:pie'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + SliceID_TBL.mutex.synchronize{ SliceID_TBL.clear } + } def self.id2obj(pie, id) pie_path = pie.path - return id unless SliceID_TBL[pie_path] - SliceID_TBL[pie_path][id]? SliceID_TBL[pie_path][id]: id + SliceID_TBL.mutex.synchronize{ + if SliceID_TBL[pie_path] + SliceID_TBL[pie_path][id]? SliceID_TBL[pie_path][id]: id + else + id + end + } end def initialize(parent, *args) @@ -131,10 +144,14 @@ class Tk::Vu::PieSlice end @parent = @pie = parent @ppath = parent.path - @path = @id = Pie_Slice_ID.join(TkCore::INTERP._ip_id_) - SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] - SliceID_TBL[@ppath][@id] = self - Pie_Slice_ID[1].succ! + Pie_Slice_ID.mutex.synchronize{ + @path = @id = Pie_Slice_ID.join(TkCore::INTERP._ip_id_) + Pie_Slice_ID[1].succ! + } + SliceID_TBL.mutex.synchronize{ + SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] + SliceID_TBL[@ppath][@id] = self + } if args[-1].kind_of?(Hash) keys = args.unshift @@ -209,22 +226,48 @@ end class Tk::Vu::NamedPieSlice def self.new(parent, name, *args) - if SliceID_TBL[parent.path] && SliceID_TBL[parent.path][name] - return SliceID_TBL[parent.path][name] - else - super(parent, name, *args) - end + obj = nil + SliceID_TBL.mutex.synchronize{ + if SliceID_TBL[parent.path] && SliceID_TBL[parent.path][name] + obj = SliceID_TBL[parent.path][name] + else + #super(parent, name, *args) + unless parent.kind_of?(Tk::Vu::Pie) + fail ArgumentError, "expect a Tk::Vu::Pie instance for 1st argument" + end + obj = self.allocate + obj.instance_eval{ + @parent = @pie = parent + @ppath = parent.path + @path = @id = name.to_s + SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] + SliceID_TBL[@ppath][@id] = self + } + end + } + obj.instance_eval{ + if args[-1].kind_of?(Hash) + keys = args.unshift + end + @pie.set(@id, *args) + configure(keys) + } + + obj end def initialize(parent, name, *args) + # dummy:: not called by 'new' method unless parent.kind_of?(Tk::Vu::Pie) fail ArgumentError, "expect a Tk::Vu::Pie instance for 1st argument" end @parent = @pie = parent @ppath = parent.path @path = @id = name.to_s - SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] - SliceID_TBL[@ppath][@id] = self + SliceID_TBL.mutex.synchronize{ + SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] + SliceID_TBL[@ppath][@id] = self + } if args[-1].kind_of?(Hash) keys = args.unshift diff --git a/ext/tk/lib/tkextlib/winico/winico.rb b/ext/tk/lib/tkextlib/winico/winico.rb index c53a3ff48..30fb9682d 100644 --- a/ext/tk/lib/tkextlib/winico/winico.rb +++ b/ext/tk/lib/tkextlib/winico/winico.rb @@ -34,10 +34,15 @@ end class Tk::Winico WinicoID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ WinicoID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + WinicoID_TBL.mutex.synchronize{ WinicoID_TBL.clear } + } def self.id2obj(id) - (WinicoID_TBL.key?(id))? WinicoID_TBL[id] : id + WinicoID_TBL.mutex.synchronize{ + (WinicoID_TBL.key?(id))? WinicoID_TBL[id] : id + } end def self.info @@ -81,7 +86,9 @@ class Tk::Winico "must be given proper information from where loading icons" end @path = @id - WinicoID_TBL[@id] = self + WinicoID_TBL.mutex.synchronize{ + WinicoID_TBL[@id] = self + } end def id @@ -96,7 +103,9 @@ class Tk::Winico def delete tk_call('winico', 'delete', @id) - WinicoID_TBL.delete(@id) + WinicoID_TBL.mutex.synchronize{ + WinicoID_TBL.delete(@id) + } self end alias destroy delete @@ -126,15 +135,37 @@ class Tk::Winico [ ?n, TkComm.method(:number) ], [ ?s, TkComm.method(:string) ], [ ?x, proc{|id| - if Tk::Winico::WinicoID_TBL.key?(id) - Tk::Winico::WinicoID_TBL[id] - else - Tk::Winico.new(nil, nil, id) - end + Tk::Winico::WinicoID_TBL.mutex.synchronize{ + if Tk::Winico::WinicoID_TBL.key?(id) + obj = Tk::Winico::WinicoID_TBL[id] + else + # Tk::Winico.new(nil, nil, id) + obj = Tk::Winico.allocate + obj.instance_eval{ @path = @id = id } + Tk::Winico::WinicoID_TBL[id] = obj + end + obj + } } ], nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) diff --git a/ext/tk/sample/binstr_usage.rb b/ext/tk/sample/binstr_usage.rb index 91692856f..be8399ba5 100644 --- a/ext/tk/sample/binstr_usage.rb +++ b/ext/tk/sample/binstr_usage.rb @@ -16,7 +16,7 @@ to avoid such troubles. Please see the source code of this sample. \ A Tk::BinaryString instance is used to create the image for the center button. EOM -ImgFile=['images','tcllogo.gif'].join(File::Separator) +ImgFile=[File.dirname(__FILE__), 'images','tcllogo.gif'].join(File::Separator) ph1 = TkPhotoImage.new(:file=>ImgFile) p ph1.configinfo @@ -28,12 +28,18 @@ ph2 = TkPhotoImage.new(:data=>b_str) p ph2.configinfo p ph2.data(:grayscale=>true) -ph3 = TkPhotoImage.new() -ph3.put(ph2.data(:grayscale=>true)) +ph3 = TkPhotoImage.new(:palette=>256) +ph3.put(ph2.data) + +ph4 = TkPhotoImage.new() +ph4.put(ph2.data(:grayscale=>true)) + +#p [b_str.encoding, b_str.rb_encoding] f = TkFrame.new.pack TkButton.new(:parent=>f, :image=>ph1, :command=>proc{exit}).pack(:side=>:left) TkButton.new(:parent=>f, :image=>ph2, :command=>proc{exit}).pack(:side=>:left) TkButton.new(:parent=>f, :image=>ph3, :command=>proc{exit}).pack(:side=>:left) +TkButton.new(:parent=>f, :image=>ph4, :command=>proc{exit}).pack(:side=>:left) Tk.mainloop diff --git a/ext/tk/sample/demos-en/arrow.rb b/ext/tk/sample/demos-en/arrow.rb index b62e1966e..4a589a089 100644 --- a/ext/tk/sample/demos-en/arrow.rb +++ b/ext/tk/sample/demos-en/arrow.rb @@ -77,11 +77,19 @@ def arrowSetup(c) 'arrow'=>'both', 'arrowshape'=>v.smallTips) TkcText.new(c, v.x2-5*v.b, tmp+5, 'text'=>v.b, 'anchor'=>'n') - TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') - TkcText.new(c, v.x1, 330, - 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]", 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') + if $tk_version =~ /^4.*/ + TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', + 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') + TkcText.new(c, v.x1, 330, + 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]",'anchor'=>'w', + 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') + else + TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', + 'font'=>'Helvetica 18') + TkcText.new(c, v.x1, 330, + 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]", + 'anchor'=>'w', 'font'=>'Helvetica 18') + end v.count += 1 end diff --git a/ext/tk/sample/demos-en/bind.rb b/ext/tk/sample/demos-en/bind.rb index b7e7122c5..5d6ec84ed 100644 --- a/ext/tk/sample/demos-en/bind.rb +++ b/ext/tk/sample/demos-en/bind.rb @@ -43,11 +43,11 @@ def tag_binding_for_bind_demo(tag, enter_style, leave_style) end # text -TkText.new($bind_demo){|t| +txt = TkText.new($bind_demo){|t| # setgrid 'true' - width 60 - height 24 + #width 60 + #height 24 font $font wrap 'word' TkScrollbar.new($bind_demo) {|s| @@ -120,3 +120,6 @@ TkText.new($bind_demo){|t| TkTextMarkInsert.new(t, '0.0') configure('state','disabled') } + +txt.width 60 +txt.width 24 diff --git a/ext/tk/sample/demos-en/ctext.rb b/ext/tk/sample/demos-en/ctext.rb index dbb5e3263..8c10880ed 100644 --- a/ext/tk/sample/demos-en/ctext.rb +++ b/ext/tk/sample/demos-en/ctext.rb @@ -56,19 +56,28 @@ $ctext_canvas = TkCanvas.new($ctext_demo, 'relief'=>'flat', $ctext_canvas.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'both') # font -textFont = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' +if $tk_version =~ /^4.*/ + textFont = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' +else + textFont = 'Helvetica 24' +end # canvas TkcRectangle.new($ctext_canvas, 245, 195, 255, 205, 'outline'=>'black', 'fill'=>'red') +ctag_text_param = { + 'text'=>"This is just a string of text to demonstrate the text facilities of canvas widgets. Bindings have been been defined to support editing (see above).", + 'width'=>440, 'anchor'=>'n', 'justify'=>'left' +} +if $tk_version =~ /^4.*/ + ctag_text_param['font'] = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' +else + ctag_text_param['font'] = 'Helvetica 24' +end + $ctag_text = TkcTag.new($ctext_canvas) -$ctag_text.withtag(TkcText.new($ctext_canvas, 250, 200, - 'text'=>"This is just a string of text to demonstrate the text facilities of canvas widgets. Bindings have been been defined to support editing (see above).", - 'width'=>440, 'anchor'=>'n', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*', - 'kanjifont'=>'-*--24-*-jisx0208.1983-0', - 'justify'=>'left') ) +$ctag_text.withtag(TkcText.new($ctext_canvas, 250, 200, ctag_text_param)) $ctag_text.bind('1', proc{|x,y| textB1Press $ctext_canvas,x,y}, "%x %y") $ctag_text.bind('B1-Motion', proc{|x,y| textB1Move $ctext_canvas,x,y}, "%x %y") @@ -110,9 +119,14 @@ mkTextConfig $ctext_canvas, x+60, y+60, 'anchor', 'nw', color item = TkcRectangle.new($ctext_canvas, x+40, y+40, x+50, y+50, 'outline'=>'black', 'fill'=>'red') item.bind('1', proc{$ctag_text.configure 'anchor', 'center'}) -TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', 'anchor'=>'s', - 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', - 'fill'=>'brown') +if $tk_version =~ /^4.*/ + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', + 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', + 'anchor'=>'s', 'fill'=>'brown') +else + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', + 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown') +end # Lastly, create some items that allow the text's justification to be # changed. @@ -123,9 +137,14 @@ color = 'SeaGreen2' mkTextConfig $ctext_canvas, x, y, 'justify', 'left', color mkTextConfig $ctext_canvas, x+30, y, 'justify', 'center', color mkTextConfig $ctext_canvas, x+60, y, 'justify', 'right', color -TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', 'anchor'=>'s', - 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', - 'fill'=>'brown') +if $tk_version =~ /^4.*/ + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', + 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', + 'anchor'=>'s', 'fill'=>'brown') +else + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', + 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown') +end $ctext_canvas.itembind('config', 'Enter', proc{textEnter $ctext_canvas}) $ctext_canvas.itembind('config', 'Leave', diff --git a/ext/tk/sample/demos-en/hello b/ext/tk/sample/demos-en/hello index f06eabe51..5e86ad7e3 100644 --- a/ext/tk/sample/demos-en/hello +++ b/ext/tk/sample/demos-en/hello @@ -1,9 +1,9 @@ #!/usr/bin/env ruby require 'tk' -unless /^8\.[1-9]/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK - require 'tkencoding' -end +#unless /^8\.[1-9]/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK +# require 'tkencoding' +#end TkButton.new(nil, 'text'=>"Hello Ruby world!", diff --git a/ext/tk/sample/demos-en/hscale.rb b/ext/tk/sample/demos-en/hscale.rb index 14e395b61..743c4b485 100644 --- a/ext/tk/sample/demos-en/hscale.rb +++ b/ext/tk/sample/demos-en/hscale.rb @@ -62,7 +62,6 @@ TkFrame.new($hscale_demo) {|frame| scale.set 75 }.pack('side'=>'top', 'fill'=>'x') - def setWidth(w, width) width = width + 21 x2 = width - 30 @@ -72,3 +71,4 @@ def setWidth(w, width) w.coords 'poly',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15 w.coords 'line',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15 end + diff --git a/ext/tk/sample/demos-en/items.rb b/ext/tk/sample/demos-en/items.rb index 8ab7668a0..23191b59b 100644 --- a/ext/tk/sample/demos-en/items.rb +++ b/ext/tk/sample/demos-en/items.rb @@ -94,8 +94,13 @@ TkcLine.new(cvs, '0c', '16c', '30c', '16c', 'width'=>2) TkcLine.new(cvs, '10c', '0c', '10c', '24c', 'width'=>2) TkcLine.new(cvs, '20c', '0c', '20c', '24c', 'width'=>2) -font1 = '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' -font2 = '-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*' +if $tk_version =~ /^4.*/ + font1 = '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' + font2 = '-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*' +else + font1 = 'Helvetica 12' + font2 = 'Helvetica 24 bold' +end if TkWinfo.depth($root).to_i > 1 blue = 'DeepSkyBlue3' red = 'red' diff --git a/ext/tk/sample/demos-en/patch_1.1c1 b/ext/tk/sample/demos-en/patch_1.1c1 deleted file mode 100644 index d3952e71e..000000000 --- a/ext/tk/sample/demos-en/patch_1.1c1 +++ /dev/null @@ -1,93 +0,0 @@ ---- /usr/src/ruby-1.1c1/lib/tkcanvas.rb Tue Jul 21 18:18:02 1998 -+++ tkcanvas.rb Fri Jul 24 20:38:24 1998 -@@ -310,7 +310,7 @@ - || key == 'latinfont' || key == 'asciifont' ) - tagfont_configure(tagid(tagOrId), {key=>value}) - else -- tk_call 'itemconfigure', tagid(tagOrId), "-#{key}", value -+ tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value - end - end - end ---- /usr/src/ruby-1.1c1/lib/tkfont.rb Fri Jul 17 23:43:28 1998 -+++ tkfont.rb Fri Jul 24 17:46:22 1998 -@@ -42,7 +42,7 @@ - r | [] - - when /^8\.*/ -- list(tk_call('font', 'names')) -+ tk_split_simplelist(tk_call('font', 'names')) - - end - end -@@ -89,10 +89,14 @@ - if fnt == [] - TkFont.new(nil, nil).call_font_configure(path, *(args + [{}])) - else -- compound = Hash[*list(tk_call('font', 'configure', -- fnt))].collect{|key,value| -- [key[1..-1], value] -- }.assoc('compound')[1] -+ begin -+ compound = Hash[*list(tk_call('font', 'configure', -+ fnt))].collect{|key,value| -+ [key[1..-1], value] -+ }.assoc('compound')[1] -+ rescue -+ compound = [] -+ end - if compound == [] - TkFont.new(fnt, DEFAULT_KANJI_FONT_NAME) \ - .call_font_configure(path, *(args + [{}])) -@@ -156,14 +160,19 @@ - elsif font.kind_of? Array - finfo = {} - finfo['family'] = font[0].to_s -- if font[1] && font[1] != '0' && font[1] =~ /^(|\+|-)([0-9]+)$/ -- if $1 == '-' -- finfo['pixels'] = font[1].to_s -+ if font[1] -+ fsize = font[1].to_s -+ if fsize != '0' && fsize =~ /^(|\+|-)([0-9]+)$/ -+ if $1 == '-' -+ finfo['pixels'] = $2 -+ else -+ finfo['points'] = $2 -+ end - else -- finfo['points'] = font[1].to_s -+ finfo['points'] = '13' - end - end -- finfo[2..-1].each{|style| -+ font[2..-1].each{|style| - case (style) - when 'normal' - finfo['weight'] = style -@@ -199,16 +208,19 @@ - elsif font.kind_of? Array - finfo = {} - finfo['family'] = font[0].to_s -- if font[1] && font[1] != '0' && font[1] =~ /^(|\+|-)([0-9]+)$/ -- if $1 == '-' -- finfo['pixels'] = $2 -+ if font[1] -+ fsize = font[1].to_s -+ if fsize != '0' && fsize =~ /^(|\+|-)([0-9]+)$/ -+ if $1 == '-' -+ finfo['pixels'] = $2 -+ else -+ finfo['points'] = $2 -+ end - else -- finfo['points'] = $2 -+ finfo['points'] = '13' - end -- else -- finfo['points'] = '13' - end -- finfo[2..-1].each{|style| -+ font[2..-1].each{|style| - case (style) - when 'normal' - finfo['weight'] = style diff --git a/ext/tk/sample/demos-en/rolodex-j b/ext/tk/sample/demos-en/rolodex-j deleted file mode 100644 index 27e2bc9da..000000000 --- a/ext/tk/sample/demos-en/rolodex-j +++ /dev/null @@ -1,323 +0,0 @@ -#!/usr/bin/env ruby -# -# rolodex -- -# ¤³¤Î¥¹¥¯¥ê¥×¥È¤Ï Tom LaStrange ¤Î rolodex ¤Î°ìÉô¤Ç¤¹¡£ -# -# Copyright (C) 1998 by Takaaki Tateishi <ttate@jaist.ac.jp> -# Time-stamp: "03/08/02 14:02:04 nagai" -# - -require "tk" - -Tk.encoding = "euc-jp" -$font = TkFont.new('k14') - -def show_help(topic,x=0,y=0) - if( topic.is_a?(TkWindow) ) - w = TkWinfo.containing(x,y) - if( w.is_a?(TkWindow) ) - if( TkWinfo.exist?(w) ) - topic = w - end - end - end - - if( $helpTopics.include?(topic) ) - msg = $helpTopics[topic] - else - msg = "¤³¤Î¥È¥Ô¥Ã¥¯¤Ë¤Ä¤¤¤Æ¤Î¥Ø¥ë¥×¤Ï¤Þ¤À»ÈÍѤǤ¤Þ¤»¤ó" - end - TkDialog.new("title"=>"Rolodex Help", - "message"=>"¡Ö#{topic}¡×\n\n#{msg}", - "font"=>$font, - "default_button"=>0, - "buttons"=>["OK"]) -end - -def fillCard - clearAction - $root.frame.entry[1].insert(0, "ΩÀÐ ¹§¾´") - $root.frame.entry[2].insert(0, "923-1292 ÀÐÀ") - $root.frame.entry[3].insert(0, "ä¸ýÄ® °°Âæ 1-1") - $root.frame.entry[4].insert(0, "ËÌΦÀèü²Ê³Øµ»½ÑÂç³Ø±¡Âç³Ø") - $root.frame.entry[5].insert(0,"private") - $root.frame.entry[6].insert(0,"***-***-****") - $root.frame.entry[7].insert(0,"***-***-****") -end - -def addAction - for i in 1..7 - STDERR.print format("%-12s %s\n", - RolodexFrame::LABEL[i], - $root.frame.entry[i].value) - end -end - -def clearAction - for i in 1..7 - $root.frame.entry[i].delete(0,"end") - end -end - -def fileAction - TkDialog.new("title"=>"File Selection", - "message"=>"¤³¤ì¤Ï¥Õ¥¡¥¤¥ëÁªÂò¥À¥¤¥¢¥í¥°¤Î¥À¥ß¡¼¤Ç¤¹¡£\n", - "font"=>$font, - "default_button"=>0, - "buttons"=>["OK"]) - STDERR.print "dummy file name\n" -end - -def deleteAction - result = TkDialog.new("title"=>"Confirm Action", - "message"=>"¤è¤í¤·¤¤¤Ç¤¹¤«¡©", - "font"=>$font, - "default_button"=>0, - "buttons"=>["¥¥ã¥ó¥»¥ë"]) - if( result.value == 0 ) - clearAction - end -end - - -class RolodexFrame < TkFrame - attr_reader :entry, :label - - LABEL = ["","̾Á°:","½»½ê","","","ÅÅÏÃ(¼«Âð):","ÅÅÏÃ(²ñ¼Ò):","Fax:"] - - def initialize(parent=nil,keys=nil) - super(parent,keys) - self["relief"] = "flat" - @i = [] - @label = [] - @entry = [] - for i in 1..7 - @i[i] = TkFrame.new(self) - @i[i].pack("side"=>"top", - "pady"=>2, - "anchor"=>"e") - @label[i] = TkLabel.new(@i[i], - "text"=>LABEL[i], - "anchor"=>"e", - "font" => $font) - @entry[i] = TkEntry.new(@i[i], - "width"=>30, - "relief"=>"sunken", - "font" => $font) - @entry[i].pack("side"=>"right") - @label[i].pack("side"=>"right") - end - end -end - -class RolodexButtons < TkFrame - attr_reader :clear, :add, :search, :delete - - def initialize(parent,keys=nil) - super(parent,keys) - @clear = TkButton.new(self, - "text" => "¥¯¥ê¥¢¡¼", - "font" => $font) - @add = TkButton.new(self, - "text" => "ÄɲÃ", - "font" => $font) - @search = TkButton.new(self, - "text" => "¸¡º÷", - "font" => $font) - @delete = TkButton.new(self, - "text" => "¾Ãµî", - "font" => $font) - for w in [@clear,@add,@search,@delete] - w.pack("side"=>"left", "padx"=>2) - end - end -end - -class RolodexMenuFrame < TkFrame - attr_reader :file_menu, :help_menu, :file, :help - - def initialize(parent,keys=nil) - super(parent,keys) - configure("relief"=>"raised", - "borderwidth"=>1) - - @file = TkMenubutton.new(self, - "text"=> "¥Õ¥¡¥¤¥ë", - "font"=> $font, - "underline"=>0) - @file_menu = TkMenu.new(@file) - @file_menu.add("command", - "label" => "Æɤ߹þ¤ß ...", - "font" => $font, - "command" => proc{fileAction}, - "underline" => 0) - @file_menu.add("command", - "label" => "½ªÎ»", - "font" => $font, - "command" => proc{$root.destroy}, - "underline" => 0) - @file.menu(@file_menu) - @file.pack("side"=>"left") - - @help = TkMenubutton.new(self, - "text"=> "¥Ø¥ë¥×", - "font"=> $font, - "underline"=>0) - @help_menu = TkMenu.new(@help) - @help_menu.add("command", - "label"=> "¥³¥ó¥Æ¥¥¹¥È¤Ë¤Ä¤¤¤Æ", - "font" => $font, - "command"=>proc{show_help("¥³¥ó¥Æ¥¥¹¥È")}, - "underline"=>3) - @help_menu.add("command", - "label"=> "¥Ø¥ë¥×¤Ë¤Ä¤¤¤Æ", - "font" => $font, - "command"=>proc{show_help("¥Ø¥ë¥×")}, - "underline"=>3) - @help_menu.add("command", - "label"=> "¥¦¥£¥ó¥É¥¦¤Ë¤Ä¤¤¤Æ", - "font" => $font, - "command"=>proc{show_help("¥¦¥£¥ó¥É¥¦")}, - "underline"=>3) - @help_menu.add("command", - "label"=> "¥¡¼Áàºî¤Ë¤Ä¤¤¤Æ", - "font" => $font, - "command"=>proc{show_help("¥¡¼Áàºî")}, - "underline"=>3) - @help_menu.add("command", - "label"=> "¥Ð¡¼¥¸¥ç¥ó¾ðÊó", - "font" => $font, - "command"=>proc{show_help("¥Ð¡¼¥¸¥ç¥ó¾ðÊó")}, - "underline"=>3) - @help.menu(@help_menu) - @help.pack("side"=>"right") - end -end - -class Rolodex < TkRoot - attr_reader :frame, :buttons, :menu - - def initialize(*args) - super(*args) - @frame = RolodexFrame.new(self) - @frame.pack("side"=>"top", - "fill"=>"y", - "anchor"=>"center") - @buttons = RolodexButtons.new(self) - @buttons.pack("side"=>"bottom", - "pady"=>2, - "anchor"=>"center") - @menu = RolodexMenuFrame.new(self) - @menu.pack("before"=>@frame, - "side"=>"top", - "fill"=>"x") - end -end - -$root = Rolodex.new - -$root.buttons.delete.configure("command"=>proc{deleteAction}) -$root.buttons.add.configure("command"=>proc{addAction}) -$root.buttons.clear.configure("command"=>proc{clearAction}) -$root.buttons.search.configure("command"=>proc{addAction; fillCard}) - -$root.buttons.clear.configure("text"=> "¥¯¥ê¥¢¡¼ Ctrl+C", "font" => $font) -$root.bind("Control-c",proc{clearAction}) - -$root.buttons.add.configure("text"=> "Äɲà Ctrl+A", "font" => $font) -$root.bind("Control-a",proc{addAction}) - -$root.buttons.search.configure("text"=> "¸¡º÷ Ctrl+S", "font" => $font) -$root.bind("Control-s",proc{addAction; fillCard}) - -$root.buttons.delete.configure("text"=> "¾Ãµî Ctrl+D", "font" => $font) -$root.bind("Control-d",proc{deleteAction}) - -$root.menu.file_menu.entryconfigure(1, "accel"=>"Ctrl+F") -$root.bind("Control-f",proc{fileAction}) - -$root.menu.file_menu.entryconfigure(2, "accel"=>"Ctrl+Q") -$root.bind("Control-q",proc{$root.destroy}) - -$root.frame.entry[1].focus - -$root.bind("Any-F1", - proc{|event| show_help(event.widget, event.x_root, event.y_root)}) -$root.bind("Any-Help", - proc{|event| show_help(event.widget, event.x_root, event.y_root)}) - - -$helpTopics = {} - -$helpTopics[$root.menu.file] = <<EOF -¤³¤ì¤Ï¡Ö¥Õ¥¡¥¤¥ë¡×¥á¥Ë¥å¡¼¤Ç¤¹¡£¡ÖÆɤ߹þ¤ß¡×¤ä¡Ö½ªÎ»¡×¤Ê¤É¤ò -¹Ô¤Ê¤¦¤³¤È¤¬¤Ç¤¤Þ¤¹¡£ -EOF - -$helpTopics[$root.menu.file_menu.index(0)] = <<EOF -¥Õ¥¡¥¤¥ë¤ÎÆɤ߹þ¤ß¤ò¹Ô¤Ê¤¦¤È¤¤Ë»È¤¤¤Þ¤¹¡£ -EOF - -$helpTopics[$root.menu.file_menu.index(1)] = <<EOF -¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤ò½ªÎ»¤¹¤ë¤È¤¤Ë»È¤¤¤Þ¤¹¡£ -EOF - -$helpTopics[$root.frame.entry[1]] = <<EOF -̾Á°¤òµÆþ¤¹¤ë¥¨¥ó¥È¥ê¤Ç¤¹¡£ -EOF - -$helpTopics[$root.frame.entry[2]] = <<EOF -½»½ê¤òµÆþ¤¹¤ë¥¨¥ó¥È¥ê¤Ç¤¹¡£ -EOF - -$helpTopics[$root.frame.entry[3]] = <<EOF -½»½ê¤òµÆþ¤¹¤ë¥¨¥ó¥È¥ê¤Ç¤¹¡£ -EOF - -$helpTopics[$root.frame.entry[4]] = <<EOF -½»½ê¤òµÆþ¤¹¤ë¥¨¥ó¥È¥ê¤Ç¤¹¡£ -EOF - -$helpTopics[$root.frame.entry[5]] = <<EOF -¼«Âð¤ÎÅÅÏÃÈÖ¹æ¤òµÆþ¤¹¤ë¥¨¥ó¥È¥ê¤Ç¤¹¡£¸ø³«\ -¤·¤¿¤¯¤Ê¤¤¤È¤¤Ï private ¤ÈµÆþ¤·¤Þ¤¹¡£ -EOF - -$helpTopics[$root.frame.entry[6]] = <<EOF -²ñ¼Ò¤ÎÅÅÏÃÈÖ¹æ¤òµÆþ¤¹¤ë¥¨¥ó¥È¥ê¤Ç¤¹¡£ -EOF - -$helpTopics[$root.frame.entry[7]] = <<EOF -FAXÈÖ¹æ¤òµÆþ¤¹¤ë¥¨¥ó¥È¥ê¤Ç¤¹¡£ -EOF - -$helpTopics["¥³¥ó¥Æ¥¥¹¥È"] = <<EOF -Ruby/Tk¤Ç¤Ïgrab¤Îµ¡¹½¤¬¤Ê¤¤¤¿¤á¤³¤Î¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤Ç¤Ï\ -¥³¥ó¥Æ¥¥¹¥È¥Ø¥ë¥×¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£ -¤·¤«¤·Æ±¤¸¤è¤¦¤Ê¸ú²Ì¤òbind¤È¥Þ¥¦¥¹¤Î°ÌÃÖ¤ÎWedget¤òÃΤë\ -¤³¤È¤ÇÆÀ¤ë¤³¤È¤¬¤Ç¤¤Þ¤¹¡£ -EOF - -$helpTopics["¥Ø¥ë¥×"] = <<EOF -¥Þ¥¦¥¹¤ò¥¦¥£¥ó¥É¥¦¤Ë¤¢¤ï¤»¤ÆF1¥¡¼¤ò²¡¤¹¤³¤È¤Ë¤è¤Ã¤Æ\ -¤½¤Î¥Ø¥ë¥×¤ò¸«¤ë¤³¤È¤¬¤Ç¤¤Þ¤¹¡£ -EOF - -$helpTopics["¥¦¥£¥ó¥É¥¦"] = <<EOF -¤³¤Î¥¦¥£¥ó¥É¥¦¤Ï¥À¥ß¡¼¤Ç¤¹¡£ -EOF - -$helpTopics["¥¡¼Áàºî"] = <<EOF -Ctrl+A: Äɲà -Ctrl+C: ¥¯¥ê¥¢¡¼ -Ctrl+D: ¾Ãµî -Ctrl+F: ¥Õ¥¡¥¤¥ëÁªÂò -Ctrl+Q: ½ªÎ» -Ctrl+S: ¸¡º÷ -EOF - -$helpTopics["¥Ð¡¼¥¸¥ç¥ó¾ðÊó"] = <<EOF -¥Ð¡¼¥¸¥ç¥ó¤Ï 1.0.1e ¤Ç¤¹¡£ -EOF - -Tk.mainloop diff --git a/ext/tk/sample/demos-en/search.rb b/ext/tk/sample/demos-en/search.rb index 3d3b4aecc..3749423bb 100644 --- a/ext/tk/sample/demos-en/search.rb +++ b/ext/tk/sample/demos-en/search.rb @@ -140,7 +140,7 @@ $search_text = TkText.new($search_demo, 'setgrid'=>true, 'wrap'=>'word') {|t| pack('side'=>'right', 'fill'=>'y') } pack('expand'=>'yes', 'fill'=>'both') -} +} # Set up display styles for text highlighting. @@ -173,8 +173,13 @@ type a string in the lower entry and type <Return> or click on \ \"Load File\". This will cause all of the instances of the string to \ be tagged with the tag \"search\", and it will arrange for the tag\'s \ display attributes to change to make all of the strings blink.") +$search_text.insert('end', "\ +The current directory to load a file is \"#{Dir.pwd}\".\ +") $search_text.set_insert '0.0' $search_fileName.value = '' $search_searchString.value = '' +$search_text.width = 60 +$search_text.height = 20 diff --git a/ext/tk/sample/demos-en/style.rb b/ext/tk/sample/demos-en/style.rb index 5ed11aa45..8606893c9 100644 --- a/ext/tk/sample/demos-en/style.rb +++ b/ext/tk/sample/demos-en/style.rb @@ -40,9 +40,10 @@ TkFrame.new($style_demo) {|frame| TkText.new($style_demo){|t| # setgrid 'true' - width 70 - height 32 + #width 70 + #height 32 wrap 'word' + font $font TkScrollbar.new($style_demo) {|s| pack('side'=>'right', 'fill'=>'y') command proc{|*args| t.yview(*args)} @@ -51,11 +52,20 @@ TkText.new($style_demo){|t| pack('expand'=>'yes', 'fill'=>'both') # - style_tag_bold = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-O-Normal--*-120-*-*-*-*-*-*') - style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font) + family = 'Courier' + + if $tk_version =~ /^4.*/ + style_tag_bold = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-O-Normal--*-120-*-*-*-*-*-*') + style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font) style_tag_verybig = TkTextTag.new(t, 'font'=>'-*-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*') -# style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font) + # style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font) style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*') + else + style_tag_bold = TkTextTag.new(t, 'font'=>[family, 12, :bold, :italic]) + style_tag_big = TkTextTag.new(t, 'font'=>[family, 14, :bold]) + style_tag_verybig = TkTextTag.new(t, 'font'=>['Helvetica', 24, :bold]) + style_tag_small = TkTextTag.new(t, 'font'=>['Times 8 bold']) + end ### # case($tk_version) # when /^4.*/ @@ -109,8 +119,13 @@ TkText.new($style_demo){|t| style_tag_overstrike = TkTextTag.new(t, 'overstrike'=>'on') style_tag_right = TkTextTag.new(t, 'justify'=>'right') style_tag_center = TkTextTag.new(t, 'justify'=>'center') - style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') - style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') + if $tk_version =~ /^4.*/ + style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') + style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') + else + style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>[family, 10]) + style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>[family, 10]) + end style_tag_margins = TkTextTag.new(t, 'lmargin1'=>'12m', 'lmargin2'=>'6m', 'rmargin'=>'10m') style_tag_spacing = TkTextTag.new(t, 'spacing1'=>'10p', 'spacing2'=>'2p', @@ -132,7 +147,8 @@ available display styles are: insert('end', " You can choose any X font, ") insert('end', "large", style_tag_verybig) insert('end', " or ") - insert('end', "small.\n") + insert('end', "small", style_tag_small) + insert('end', ".\n") insert('end', "\n2. Color.", style_tag_big) insert('end', " You can change either the ") insert('end', "background", style_tag_color1) @@ -209,3 +225,5 @@ available display styles are: } +txt.width 70 +txt.height 32 diff --git a/ext/tk/sample/demos-en/textpeer.rb b/ext/tk/sample/demos-en/textpeer.rb new file mode 100644 index 000000000..d98ef170b --- /dev/null +++ b/ext/tk/sample/demos-en/textpeer.rb @@ -0,0 +1,72 @@ +# +# text widget peering demo (called by 'widget') +# +# based on Tcl/Tk8.5.0 widget demos + +if defined?($textpeer_demo) && $textpeer_demo + $textpeer_demo.destroy + $textpeer_demo = nil +end + +# demo toplevel widget +$textpeer_demo = TkToplevel.new {|w| + title("Text Wdget Peering Demonstration") + iconname("textpeer") + positionWindow(w) +} + +count = [0] + +## Define a widget that we peer from; it won't ever actually be shown though +first = TkText.new($textpeer_demo, :widgetname=>"text#{count[0] += 1}") +first.insert :end,"This is a coupled pair of text widgets; they are peers to " +first.insert :end,"each other. They have the same underlying data model, but " +first.insert :end,"can show different locations, have different current edit " +first.insert :end,"locations, and have different selections. You can also " +first.insert :end,"create additional peers of any of these text widgets using " +first.insert :end,"the Make Peer button beside the text widget to clone, and " +first.insert :end,"delete a particular peer widget using the Delete Peer " +first.insert :end,"button." + +## Procedures to make and kill clones; most of this is just so that the demo +## looks nice... +def makeClone(count, win, txt) + cnt = (count[0] += 1) + peer = TkText::Peer.new(txt, win, :widgetname=>"text#{cnt}") + sbar = TkScrollbar.new(win, :widgetname=>"sb#{cnt}") + peer.yscrollbar sbar + b1 = TkButton.new(win, :widgetname=>"clone#{cnt}", :text=>'Make Peer', + :command=>proc{makeClone(count, win, peer)}) + b2 = TkButton.new(win, :widgetname=>"kill#{cnt}", :text=>'Delete Peer', + :command=>proc{killClone(win, cnt)}) + row = cnt * 2 + TkGrid.configure(peer, sbar, b1, :sticky=>'nsew', :row=>row) + TkGrid.configure('^', '^', b2, :sticky=>'nsew', :row=>(row+=1)) + TkGrid.configure(b1, b2, :sticky=>'new') + TkGrid.rowconfigure(win, b2, :weight=>1) +end + +def killClone(win, cnt) + Tk.destroy("#{win.path}.text#{cnt}", "#{win.path}.sb#{cnt}", + "#{win.path}.clone#{cnt}", "#{win.path}.kill#{cnt}") +end + +## Now set up the GUI +makeClone(count, $textpeer_demo, first) +makeClone(count, $textpeer_demo, first) +first.destroy + +## See Code / Dismiss buttons +TkFrame.new($textpeer_demo){|f| + TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{ + $textpeer_demo.destroy + $textpeer_demo = nil + }).pack(:side=>:left, :expand=>true) + + TkButton.new(f, :text=>'See Code', :width=>15, :command=>proc{ + showCode 'textpeer' + }).pack(:side=>:left, :expand=>true) + + TkGrid.configure(f, '-', '-', :sticky=>'ew', :row=>5000) +} +TkGrid.columnconfigure($textpeer_demo, 0, :weight=>1) diff --git a/ext/tk/sample/demos-en/twind.rb b/ext/tk/sample/demos-en/twind.rb index 24a4bcf70..f29e49f35 100644 --- a/ext/tk/sample/demos-en/twind.rb +++ b/ext/tk/sample/demos-en/twind.rb @@ -206,7 +206,11 @@ def textWindPlot (t) cursor 'top_left_arrow' } - font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' + if $tk_version =~ /^4.*/ + font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' + else + font = 'Helvetica 18' + end TkcLine.new($twind_plot, 100, 250, 400, 250, 'width'=>2) TkcLine.new($twind_plot, 100, 250, 100, 50, 'width'=>2) diff --git a/ext/tk/sample/demos-en/vscale.rb b/ext/tk/sample/demos-en/vscale.rb index 636b85813..c0170467d 100644 --- a/ext/tk/sample/demos-en/vscale.rb +++ b/ext/tk/sample/demos-en/vscale.rb @@ -66,7 +66,6 @@ TkFrame.new($vscale_demo) {|frame| scale.set 75 }.pack - def setHeight(w, height) height = height + 21 y2 = height - 30 diff --git a/ext/tk/sample/demos-en/widget b/ext/tk/sample/demos-en/widget index 3c5058221..391d8532b 100644 --- a/ext/tk/sample/demos-en/widget +++ b/ext/tk/sample/demos-en/widget @@ -21,7 +21,8 @@ require 'tk' #---------------------------------------------------------------- # widget demo directory -$demo_dir = File.dirname($0) +# $demo_dir = File.dirname($0) +$demo_dir = File.dirname(__FILE__) # root $root = TkRoot.new{title "Ruby/Tk Widget Demonstration"} @@ -164,12 +165,17 @@ else textFrame.pack('expand'=>'yes', 'fill'=>'both') statusBar = TkFrame.new($root) {|f| + if $tk_version =~ /^4.*/ + statusfont = '-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' + else + statusfont = 'Helvetica 10' + end $statusBarLabel = \ TkLabel.new(f, 'text'=>" ", 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') \ + 'font'=>statusfont) \ .pack('side'=>'left', 'padx'=>2, 'expand'=>'yes', 'fill'=>'both') TkLabel.new(f, 'width'=>8, 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') \ + 'font'=>statusfont) \ .pack('side'=>'left', 'padx'=>2) }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>2) end @@ -178,7 +184,11 @@ end # section titles and demo descriptions. Also define the bindings for # tags. -tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*') +if $tk_version =~ /^4.*/ + tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*') +else + tag_title = TkTextTag.new(txt, 'font'=>'Helvetica 18 bold') +end # We put some "space" characters to the left and right of each demo description # so that the descriptions are highlighted only when the mouse cursor @@ -331,6 +341,8 @@ txt.insert('end', "5. A text widget with embedded windows. (if supported)\n", ta txt.insert('end', " \n ", tag_demospace) txt.insert('end', "6. A search tool built with a text widget.\n", tag_demo, "demo-search") txt.insert('end', " \n ", tag_demospace) +txt.insert('end', "7. Peering text widgets. (if supported)\n", tag_demo, "demo-textpeer") +txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") txt.insert('end', "Canvases\n", tag_title) @@ -445,7 +457,11 @@ def showVars1(parent, *args) text "Variable values:" width 20 anchor 'center' - font '-Adobe-helvetica-medium-r-normal--*-180-*-*-*-*-*-*' + if $tk_version =~ /^4.*/ + font '-Adobe-helvetica-medium-r-normal--*-180-*-*-*-*-*-*' + else + font 'Helvetica 14' + end }.pack('side'=>'top', 'fill'=>'x') len = 1 args.each{|vnam,vbody| @@ -592,7 +608,9 @@ end private :_null_binding def eval_samplecode(code) - Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } }.run + #eval(code) + #_null_binding.pseudo_toplevel_eval{ eval(code) } + Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } } Tk.update end @@ -896,7 +914,7 @@ end # def aboutBox Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo', - 'message'=>"Ruby/Tk widget demonstration Ver.1.6.0-en\n\n" + + 'message'=>"Ruby/Tk widget demonstration Ver.1.6.3-en\n\n" + "based on demos of Tk8.1 -- 8.5 " + "( Copyright:: " + "(c) 1996-1997 Sun Microsystems, Inc. / " + diff --git a/ext/tk/sample/demos-jp/arrow.rb b/ext/tk/sample/demos-jp/arrow.rb index 43c6eef4e..b2c106702 100644 --- a/ext/tk/sample/demos-jp/arrow.rb +++ b/ext/tk/sample/demos-jp/arrow.rb @@ -74,11 +74,19 @@ def arrowSetup(c) 'arrow'=>'both', 'arrowshape'=>v.smallTips) TkcText.new(c, v.x2-5*v.b, tmp+5, 'text'=>v.b, 'anchor'=>'n') - TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') - TkcText.new(c, v.x1, 330, - 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]", 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') + if $tk_version =~ /^4.*/ + TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', + 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') + TkcText.new(c, v.x1, 330, + 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]",'anchor'=>'w', + 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') + else + TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', + 'font'=>'Helvetica 18') + TkcText.new(c, v.x1, 330, + 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]", + 'anchor'=>'w', 'font'=>'Helvetica 18') + end v.count += 1 end diff --git a/ext/tk/sample/demos-jp/bind.rb b/ext/tk/sample/demos-jp/bind.rb index 87b39721d..3b6f6242c 100644 --- a/ext/tk/sample/demos-jp/bind.rb +++ b/ext/tk/sample/demos-jp/bind.rb @@ -41,11 +41,11 @@ def tag_binding_for_bind_demo(tag, enter_style, leave_style) end # text À¸À® -TkText.new($bind_demo){|t| +txt = TkText.new($bind_demo){|t| # À¸À® setgrid 'true' - width 60 - height 24 + #width 60 + #height 24 font $font wrap 'word' TkScrollbar.new($bind_demo) {|s| @@ -118,3 +118,6 @@ TkText.new($bind_demo){|t| TkTextMarkInsert.new(t, '0.0') configure('state','disabled') } + +txt.width 60 +txt.width 24 diff --git a/ext/tk/sample/demos-jp/ctext.rb b/ext/tk/sample/demos-jp/ctext.rb index 35d43febb..f5daf7ca0 100644 --- a/ext/tk/sample/demos-jp/ctext.rb +++ b/ext/tk/sample/demos-jp/ctext.rb @@ -53,19 +53,28 @@ $ctext_canvas = TkCanvas.new($ctext_demo, 'relief'=>'flat', $ctext_canvas.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'both') # font ÀßÄê -textFont = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' +if $tk_version =~ /^4.*/ + textFont = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' +else + textFont = 'Helvetica 24' +end # canvas ÀßÄê TkcRectangle.new($ctext_canvas, 245, 195, 255, 205, 'outline'=>'black', 'fill'=>'red') +ctag_text_param = { + 'text'=>"¤³¤ì¤Ï¥¥ã¥ó¥Ð¥¹widget¤Î¥Æ¥¥¹¥Èµ¡Ç½¤ò¥Ç¥â¤¹¤ë¤¿¤á¤Îʸ»úÎó¤Ç¤¹¡£\n¾å¤Ç½Ò¤Ù¤¿¤è¤¦¤ÊÊÔ½¸¤ò²Äǽ¤È¤¹¤ë¤¿¤á¤Î¥Ð¥¤¥ó¥Ç¥£¥ó¥°¤ò»Ü¤·¤Æ¤¤¤Þ¤¹¡£", + 'width'=>440, 'anchor'=>'n', 'justify'=>'left' +} +if $tk_version =~ /^4.*/ + ctag_text_param['font'] = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' + ctag_text_param['kanjifont'] = '-*-r-*--24-*-jisx0208.1983-0' +else + ctag_text_param['font'] = 'Helvetica 24' +end $ctag_text = TkcTag.new($ctext_canvas) -$ctag_text.withtag(TkcText.new($ctext_canvas, 250, 200, - 'text'=>"¤³¤ì¤Ï¥¥ã¥ó¥Ð¥¹widget¤Î¥Æ¥¥¹¥Èµ¡Ç½¤ò¥Ç¥â¤¹¤ë¤¿¤á¤Îʸ»úÎó¤Ç¤¹¡£\n¾å¤Ç½Ò¤Ù¤¿¤è¤¦¤ÊÊÔ½¸¤ò²Äǽ¤È¤¹¤ë¤¿¤á¤Î¥Ð¥¤¥ó¥Ç¥£¥ó¥°¤ò»Ü¤·¤Æ¤¤¤Þ¤¹¡£", - 'width'=>440, 'anchor'=>'n', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*', - 'kanjifont'=>'-*-r-*--24-*-jisx0208.1983-0', - 'justify'=>'left') ) +$ctag_text.withtag(TkcText.new($ctext_canvas, 250, 200, ctag_text_param)) $ctag_text.bind('1', proc{|x,y| textB1Press $ctext_canvas,x,y}, "%x %y") $ctag_text.bind('B1-Motion', proc{|x,y| textB1Move $ctext_canvas,x,y}, "%x %y") @@ -107,9 +116,14 @@ mkTextConfig $ctext_canvas, x+60, y+60, 'anchor', 'nw', color item = TkcRectangle.new($ctext_canvas, x+40, y+40, x+50, y+50, 'outline'=>'black', 'fill'=>'red') item.bind('1', proc{$ctag_text.configure 'anchor', 'center'}) -TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', 'anchor'=>'s', - 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', - 'fill'=>'brown') +if $tk_version =~ /^4.*/ + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', + 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', + 'anchor'=>'s', 'fill'=>'brown') +else + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', + 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown') +end # Lastly, create some items that allow the text's justification to be # changed. @@ -120,9 +134,14 @@ color = 'SeaGreen2' mkTextConfig $ctext_canvas, x, y, 'justify', 'left', color mkTextConfig $ctext_canvas, x+30, y, 'justify', 'center', color mkTextConfig $ctext_canvas, x+60, y, 'justify', 'right', color -TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', 'anchor'=>'s', - 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', - 'fill'=>'brown') +if $tk_version =~ /^4.*/ + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', + 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', + 'anchor'=>'s', 'fill'=>'brown') +else + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', + 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown') +end $ctext_canvas.itembind('config', 'Enter', proc{textEnter $ctext_canvas}) $ctext_canvas.itembind('config', 'Leave', diff --git a/ext/tk/sample/demos-jp/hscale.rb b/ext/tk/sample/demos-jp/hscale.rb index 690479d6d..b636f0579 100644 --- a/ext/tk/sample/demos-jp/hscale.rb +++ b/ext/tk/sample/demos-jp/hscale.rb @@ -66,7 +66,6 @@ TkFrame.new($hscale_demo) {|frame| scale.set 75 }.pack('side'=>'top', 'fill'=>'x') - def setWidth(w, width) width = width + 21 x2 = width - 30 diff --git a/ext/tk/sample/demos-jp/items.rb b/ext/tk/sample/demos-jp/items.rb index d538fac75..c173d3b57 100644 --- a/ext/tk/sample/demos-jp/items.rb +++ b/ext/tk/sample/demos-jp/items.rb @@ -92,8 +92,13 @@ TkcLine.new(cvs, '0c', '16c', '30c', '16c', 'width'=>2) TkcLine.new(cvs, '10c', '0c', '10c', '24c', 'width'=>2) TkcLine.new(cvs, '20c', '0c', '20c', '24c', 'width'=>2) -font1 = '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' -font2 = '-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*' +if $tk_version =~ /^4.*/ + font1 = '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' + font2 = '-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*' +else + font1 = 'Helvetica 12' + font2 = 'Helvetica 24 bold' +end if TkWinfo.depth($root).to_i > 1 blue = 'DeepSkyBlue3' red = 'red' diff --git a/ext/tk/sample/demos-jp/plot.rb b/ext/tk/sample/demos-jp/plot.rb index 09a344683..dbca3e971 100644 --- a/ext/tk/sample/demos-jp/plot.rb +++ b/ext/tk/sample/demos-jp/plot.rb @@ -42,7 +42,11 @@ $plot_buttons = TkFrame.new($plot_demo) {|frame| $plot_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # font ÀßÄê -plotFont = '-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' + if $tk_version =~ /^4.*/ + plotFont = '-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' + else + font = 'Helvetica 18' + end # canvas ÀßÄê $plot_canvas = TkCanvas.new($plot_demo,'relief'=>'raised','width'=>450,'height'=>300) diff --git a/ext/tk/sample/demos-jp/search.rb b/ext/tk/sample/demos-jp/search.rb index adb72fd80..d3692e245 100644 --- a/ext/tk/sample/demos-jp/search.rb +++ b/ext/tk/sample/demos-jp/search.rb @@ -169,9 +169,14 @@ $search_text.insert('1.0', "\ ¥¨¥ó¥È¥ê¤Ëʸ»úÎó¤òÆþÎϤ·¡¢<¥ê¥¿¡¼¥ó> ¤ò²¡¤¹¤«¡Öȿž¡×¥Ü¥¿¥ó¤ò²¡¤·¤Æ¤¯ \ ¤À¤µ¤¤¡£¤¹¤ë¤È¥Õ¥¡¥¤¥ëÃæ¤Î¡¢¸¡º÷ʸ»úÎó¤È°ìÃפ¹¤ëÉôʬ¤ËÁ´¤Æ \"search_Tag\" \ ¤È¤¤¤¦¥¿¥°¤¬¤Ä¤±¤é¤ì¡¢¥¿¥°¤Îɽ¼¨Â°À¤È¤·¤Æ¤½¤Îʸ»úÎó¤¬ÅÀÌǤ¹¤ë¤è¤¦¤Ë \ -ÀßÄꤵ¤ì¤Þ¤¹¡£") +ÀßÄꤵ¤ì¤Þ¤¹¡£\n") +$search_text.insert('end', "\ +¥Õ¥¡¥¤¥ëÆɤ߹þ¤ß¤Î¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤Ï \"#{Dir.pwd}\" ¤Ç¤¹¡£\ +") $search_text.set_insert '0.0' $search_fileName.value = '' $search_searchString.value = '' +$search_text.width = 60 +$search_text.height = 20 diff --git a/ext/tk/sample/demos-jp/style.rb b/ext/tk/sample/demos-jp/style.rb index 50855a549..c8c785015 100644 --- a/ext/tk/sample/demos-jp/style.rb +++ b/ext/tk/sample/demos-jp/style.rb @@ -9,6 +9,7 @@ if defined?($style_demo) && $style_demo $style_demo = nil end + # demo ÍѤΠtoplevel widget ¤òÀ¸À® $style_demo = TkToplevel.new {|w| title("Text Demonstration - Display Styles") @@ -16,6 +17,7 @@ $style_demo = TkToplevel.new {|w| positionWindow(w) } + # frame À¸À® TkFrame.new($style_demo) {|frame| TkButton.new(frame) { @@ -34,13 +36,15 @@ TkFrame.new($style_demo) {|frame| }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') + # text À¸À® -TkText.new($style_demo){|t| +txt = TkText.new($style_demo){|t| # À¸À® setgrid 'true' - width 70 - height 32 + #width 70 + #height 32 wrap 'word' + font $font TkScrollbar.new($style_demo) {|s| pack('side'=>'right', 'fill'=>'y') command proc{|*args| t.yview(*args)} @@ -49,11 +53,20 @@ TkText.new($style_demo){|t| pack('expand'=>'yes', 'fill'=>'both') # ¥Æ¥¥¹¥È¥¿¥°ÀßÄê (¥Õ¥©¥ó¥È´ØÏ¢) - style_tag_bold = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-O-Normal--*-120-*-*-*-*-*-*') - style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font) + family = 'Courier' + + if $tk_version =~ /^4.*/ + style_tag_bold = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-O-Normal--*-120-*-*-*-*-*-*') + style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font) style_tag_verybig = TkTextTag.new(t, 'font'=>'-*-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*') -# style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font) + # style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font) style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*') + else + style_tag_bold = TkTextTag.new(t, 'font'=>[family, 12, :bold, :italic]) + style_tag_big = TkTextTag.new(t, 'font'=>[family, 14, :bold]) + style_tag_verybig = TkTextTag.new(t, 'font'=>['Helvetica', 24, :bold]) + style_tag_small = TkTextTag.new(t, 'font'=>['Times 8 bold']) + end ### # case($tk_version) # when /^4.*/ @@ -107,8 +120,13 @@ TkText.new($style_demo){|t| style_tag_overstrike = TkTextTag.new(t, 'overstrike'=>'on') style_tag_right = TkTextTag.new(t, 'justify'=>'right') style_tag_center = TkTextTag.new(t, 'justify'=>'center') - style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') - style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') + if $tk_version =~ /^4.*/ + style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') + style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') + else + style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>[family, 10]) + style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>[family, 10]) + end style_tag_margins = TkTextTag.new(t, 'lmargin1'=>'12m', 'lmargin2'=>'6m', 'rmargin'=>'10m') style_tag_spacing = TkTextTag.new(t, 'spacing1'=>'10p', 'spacing2'=>'2p', @@ -247,3 +265,5 @@ spacing3') } +txt.width 70 +txt.height 32 diff --git a/ext/tk/sample/demos-jp/textpeer.rb b/ext/tk/sample/demos-jp/textpeer.rb new file mode 100644 index 000000000..9b2b57a69 --- /dev/null +++ b/ext/tk/sample/demos-jp/textpeer.rb @@ -0,0 +1,78 @@ +# -*- coding: euc-jp -*- +# +# text widget peering demo (called by 'widget') +# +# based on Tcl/Tk8.5.0 widget demos + +if defined?($textpeer_demo) && $textpeer_demo + $textpeer_demo.destroy + $textpeer_demo = nil +end + +# demo toplevel widget +$textpeer_demo = TkToplevel.new {|w| + title("Text Wdget Peering Demonstration") + iconname("textpeer") + positionWindow(w) +} + +count = [0] + +## Define a widget that we peer from; it won't ever actually be shown though +first = TkText.new($textpeer_demo, :widgetname=>"text#{count[0] += 1}") +first.insert :end,"¤³¤Î¥Ç¥â¤Ï°ì¤Ä¤ÎÁȤòÀ®¤·¤¿¥Æ¥¥¹¥È¥¦¥£¥¸¥§¥Ã¥È¤ò¼¨¤·¤Þ¤¹¡£" +first.insert :end,"¤½¤ì¤é¤Î¥Æ¥¥¹¥È¥¦¥£¥¸¥§¥Ã¥È¤ÏÂÐÅù(¥Ô¥¢;peer)¤Î´Ø·¸¤Ë" +first.insert :end,"¤Ê¤Ã¤Æ¤¤¤Þ¤¹¡£" +first.insert :end,"¤½¤ì¤é¤Ï¡¢´ðÈפȤʤë¥Ç¡¼¥¿¥â¥Ç¥ë¤Ï¶¦Ä̤Τâ¤Î¤ò»ý¤Á¤Þ¤¹¤¬¡¢" +first.insert :end,"²èÌÌɽ¼¨°ÌÃÖ¡¢ÊÔ½¸°ÌÃÖ¡¢ÁªÂòÈÏ°Ï(selection)¤Ë¤Ä¤¤¤Æ¤Ï" +first.insert :end,"ÆÈΩ¤Ë»ý¤Ä¤³¤È¤¬¤Ç¤¤Þ¤¹¡£" +first.insert :end,"³Æ¥Æ¥¥¹¥È¥¦¥£¥¸¥§¥Ã¥È¤ÎÏƤˤ¢¤ë" +first.insert :end,"¡Ö¥Ô¥¢(peer)¤ÎºîÀ®¡×¥Ü¥¿¥ó¤ò»È¤¨¤Ð¡¢" +first.insert :end,"¿·¤¿¤Ê¥Ô¥¢¤òÄɲ乤뤳¤È¤¬²Äǽ¤Ç¤¹¡£" +first.insert :end,"¤Þ¤¿¡Ö¥Ô¥¢(peer)¤Î¾Ãµî¡×¥Ü¥¿¥ó¤ò»È¤¨¤Ð¡¢" +first.insert :end,"ÆÃÄê¤Î¥Ô¥¢¥¦¥£¥¸¥§¥Ã¥È¤ò¾Ãµî¤¹¤ë¤³¤È¤â¤Ç¤¤Þ¤¹¡£" + +## Procedures to make and kill clones; most of this is just so that the demo +## looks nice... +def makeClone(count, win, txt) + cnt = (count[0] += 1) + peer = TkText::Peer.new(txt, win, :widgetname=>"text#{cnt}") + sbar = TkScrollbar.new(win, :widgetname=>"sb#{cnt}") + peer.yscrollbar sbar + b1 = TkButton.new(win, :widgetname=>"clone#{cnt}", + :text=>'¥Ô¥¢(peer)¤ÎºîÀ®', + :command=>proc{makeClone(count, win, peer)}) + b2 = TkButton.new(win, :widgetname=>"kill#{cnt}", + :text=>'¥Ô¥¢(peer)¤Î¾Ãµî', + :command=>proc{killClone(win, cnt)}) + row = cnt * 2 + TkGrid.configure(peer, sbar, b1, :sticky=>'nsew', :row=>row) + TkGrid.configure('^', '^', b2, :sticky=>'nsew', :row=>(row+=1)) + TkGrid.configure(b1, b2, :sticky=>'new') + TkGrid.rowconfigure(win, b2, :weight=>1) +end + +def killClone(win, cnt) + Tk.destroy("#{win.path}.text#{cnt}", "#{win.path}.sb#{cnt}", + "#{win.path}.clone#{cnt}", "#{win.path}.kill#{cnt}") +end + +## Now set up the GUI +makeClone(count, $textpeer_demo, first) +makeClone(count, $textpeer_demo, first) +first.destroy + +## See Code / Dismiss buttons +TkFrame.new($textpeer_demo){|f| + TkButton.new(f, :text=>'ÊĤ¸¤ë', :width=>15, :command=>proc{ + $textpeer_demo.destroy + $textpeer_demo = nil + }).pack(:side=>:left, :expand=>true) + + TkButton.new(f, :text=>'¥³¡¼¥É»²¾È', :width=>15, :command=>proc{ + showCode 'textpeer' + }).pack(:side=>:left, :expand=>true) + + TkGrid.configure(f, '-', '-', :sticky=>'ew', :row=>5000) +} +TkGrid.columnconfigure($textpeer_demo, 0, :weight=>1) diff --git a/ext/tk/sample/demos-jp/twind.rb b/ext/tk/sample/demos-jp/twind.rb index 166a44cdb..d0fa8ca49 100644 --- a/ext/tk/sample/demos-jp/twind.rb +++ b/ext/tk/sample/demos-jp/twind.rb @@ -207,7 +207,11 @@ def textWindPlot (t) cursor 'top_left_arrow' } - font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' + if $tk_version =~ /^4.*/ + font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' + else + font = 'Helvetica 18' + end TkcLine.new($twind_plot, 100, 250, 400, 250, 'width'=>2) TkcLine.new($twind_plot, 100, 250, 100, 50, 'width'=>2) diff --git a/ext/tk/sample/demos-jp/vscale.rb b/ext/tk/sample/demos-jp/vscale.rb index eb0cea250..990ca4321 100644 --- a/ext/tk/sample/demos-jp/vscale.rb +++ b/ext/tk/sample/demos-jp/vscale.rb @@ -67,7 +67,6 @@ TkFrame.new($vscale_demo) {|frame| scale.set 75 }.pack - def setHeight(w, height) height = height + 21 y2 = height - 30 @@ -77,3 +76,4 @@ def setHeight(w, height) w.coords 'poly',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20 w.coords 'line',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20 end + diff --git a/ext/tk/sample/demos-jp/widget b/ext/tk/sample/demos-jp/widget index 7982a6651..3eea4c788 100644 --- a/ext/tk/sample/demos-jp/widget +++ b/ext/tk/sample/demos-jp/widget @@ -5,7 +5,7 @@ if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!!!! $KCODE = 'euc' else - $TK_ENCODING = 'EUC-JP' + DEFAULT_TK_ENCODING = 'EUC-JP' end # tk ´Ø·¸¥é¥¤¥Ö¥é¥ê¤ÎÆɤ߹þ¤ß @@ -13,7 +13,8 @@ require 'tk' # require 'tkafter' # widget demo directory °ÌÃ֤γÍÆÀ -$demo_dir = File.dirname($0) +# $demo_dir = File.dirname($0) +$demo_dir = File.dirname(__FILE__) # root ¤ÎÀ¸À® $root = TkRoot.new{title "Ruby/Tk Widget Demonstration"} @@ -45,18 +46,17 @@ when /^4.*/ # $msg_kanji_font=TkFont.new('Helvetica 16', 'Gothic 16 bold') when /^8.*/ - $font = TkFont.new('Helvetica -12') - $kanji_font = TkFont.new('Helvetica -12', 'Mincho -12') + $font = TkFont.new('Helvetica 12') + $kanji_font = TkFont.new('Helvetica 12', 'Mincho 12') TkOption.add('*kanjiFont', knjfont, 'startupFile') - $msg_kanji_font=TkFont.new('Helvetica 16', 'Gothic 16 bold') + $msg_kanji_font=TkFont.new('Helvetica 18 bold', 'Gothic 18 bold') else - $font = TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*', nil) + $font = TkFont.new('Helvetica 14', nil) knjfont = '-*--16-*-jisx0208.1983-0' - $kanji_font = TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*', - knjfont) + $kanji_font = TkFont.new('Helvetic 14', knj) TkOption.add('*kanjiFont', knjfont, 'startupFile') - $msg_kanji_font=TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*', + $msg_kanji_font=TkFont.new('Helvetica 14', '-*--24-*-jisx0208.1983-0') end ####### @@ -185,18 +185,27 @@ else textFrame.pack('expand'=>'yes', 'fill'=>'both') statusBar = TkFrame.new($root) {|f| + if $tk_version =~ /^4.*/ + statusfont = '-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' + else + statusfont = 'Helvetica 10' + end $statusBarLabel = \ TkLabel.new(f, 'text'=>" ", 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') \ + 'font'=>statusfont) \ .pack('side'=>'left', 'padx'=>2, 'expand'=>'yes', 'fill'=>'both') TkLabel.new(f, 'width'=>8, 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') \ + 'font'=>statusfont) \ .pack('side'=>'left', 'padx'=>2) }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>2) end # ¥Æ¥¥¹¥È¥¿¥°ÀßÄê -tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*') +if $tk_version =~ /^4.*/ + tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*') +else + tag_title = TkTextTag.new(txt, 'font'=>'Helvetica 18 bold') +end #tag_kanji_title = TkTextTag.new(txt, 'kanjifont'=>$msg_kanji_font) #tag_middle = TkTextTag.new(txt, 'kanjifont'=>$kanji_font) tag_kanji_title = TkTextTag.new(txt, 'font'=>$msg_kanji_font) @@ -372,6 +381,8 @@ txt.insert('end', "5. ¥¦¥£¥ó¥É¥¦¤òËä¤á¹þ¤ó¤À¥Æ¥¥¹¥È (µ¡Ç½¤ËÂбþ¤·¤¿¥Ð¡¼¥¸¥ç¥ó¤Î txt.insert('end', " \n ", tag_demospace) txt.insert('end', "6. ¸¡º÷\n", tag_demo, "demo-search") txt.insert('end', " \n ", tag_demospace) +txt.insert('end', "7. ¥Æ¥¥¹¥È¥¦¥£¥¸¥§¥Ã¥È¤ÎÂÐÅù²½(peering) (µ¡Ç½¤ËÂбþ¤·¤¿¥Ð¡¼¥¸¥ç¥ó¤ÎTk¤¬É¬Í×)\n", tag_demo, "demo-textpeer") +txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") #txt.insert('end', "¥¥ã¥ó¥Ð¥¹\n", tag_middle) @@ -492,7 +503,11 @@ def showVars1(parent, *args) text "ÊÑ¿ôÃÍ:" width 20 anchor 'center' - font '-Adobe-helvetica-medium-r-normal--*-180-*-*-*-*-*-*' + if $tk_version =~ /^4.*/ + font '-Adobe-helvetica-medium-r-normal--*-180-*-*-*-*-*-*' + else + font 'Helvetica 14' + end }.pack('side'=>'top', 'fill'=>'x') len = 1 args.each{|vnam,vbody| @@ -639,7 +654,9 @@ end private :_null_binding def eval_samplecode(code) - Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } }.run + #eval(code) + #_null_binding.pseudo_toplevel_eval{ eval(code) } + Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } } Tk.update end @@ -931,7 +948,7 @@ end # def aboutBox Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo', - 'message'=>"Ruby/Tk ¥¦¥£¥¸¥§¥Ã¥È¥Ç¥â Ver.1.6.0-jp\n\n" + + 'message'=>"Ruby/Tk ¥¦¥£¥¸¥§¥Ã¥È¥Ç¥â Ver.1.6.3-jp\n\n" + "based on demos of Tk8.1 -- 8.5 " + "( Copyright:: " + "(c) 1996-1997 Sun Microsystems, Inc. / " + diff --git a/ext/tk/sample/encstr_usage.rb b/ext/tk/sample/encstr_usage.rb index 4285ec861..b22c2504a 100644 --- a/ext/tk/sample/encstr_usage.rb +++ b/ext/tk/sample/encstr_usage.rb @@ -11,7 +11,7 @@ t1 = TkText.new(:height=>5).pack t2 = TkText.new(:height=>5).pack t3 = TkText.new(:height=>5).pack -src_str = IO.readlines('iso2022-kr.txt').join +src_str = IO.readlines(File.join(File.dirname(__FILE__),'iso2022-kr.txt')).join t1.insert('end', "use neither Tk::EncodedString class nor Tk.encoding= method\n\n") @@ -23,7 +23,8 @@ t2.insert('end', t2.insert('end', enc_str) Tk.encoding = 'iso2022-kr' -t3.insert('end', "use Tk.encoding = 'iso2022-kr'\n\n") +t3.insert('end', "use Tk.encoding = 'iso2022-kr' (Tk.force_default_encoding? == #{Tk.force_default_encoding?})\n\n") + t3.insert('end', src_str) Tk.mainloop diff --git a/ext/tk/sample/irbtkw.rbw b/ext/tk/sample/irbtkw.rbw index f6a35be6e..3fb6dde62 100644 --- a/ext/tk/sample/irbtkw.rbw +++ b/ext/tk/sample/irbtkw.rbw @@ -4,7 +4,7 @@ # # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # -release = '2006/11/06' +release = '2008/03/08' require 'tk' begin @@ -15,10 +15,32 @@ end require 'irb' +if TkCore::WITH_ENCODING +else + # $KCODE setup + case Tk.encoding + when 'shiftjis', 'cp932' + $KCODE='SJIS' + when 'euc-jp' + $KCODE='EUC' + when 'utf-8', 'unicode' + $KCODE='UTF8' + else + # unknown + end +end + # console setup top = TkToplevel.new(:title=>'IRB console') top.protocol(:WM_DELETE_WINDOW){ Tk.exit } +case (Tk.windowingsystem) +when 'win32' + fnt = ['MS Gothic', '-12'] +else + fnt = ['courier', '-12'] +end + console = TkTextIO.new(top, :mode=>:console, :width=>80).pack(:side=>:left, :expand=>true, :fill=>:both) diff --git a/ext/tk/sample/tkextlib/tile/demo.rb b/ext/tk/sample/tkextlib/tile/demo.rb index b604410da..1a9c02970 100644 --- a/ext/tk/sample/tkextlib/tile/demo.rb +++ b/ext/tk/sample/tkextlib/tile/demo.rb @@ -20,6 +20,12 @@ def version?(ver) TkPackage.vcompare(Tk::Tile.package_version, ver) >= 0 end +# define Tcl/Tk procedures for compatibility +Tk::Tile.__define_LoadImages_proc_for_compatibility__! +Tk::Tile::Style.__define_wrapper_proc_for_compatibility__! + +Tk::Tile::Style.theme_create('step') + Tk.load_tclscript(File.join(demodir, 'toolbutton.tcl')) Tk.load_tclscript(File.join(demodir, 'repeater.tcl')) @@ -55,7 +61,7 @@ $V = TkVariable.new_hash(:THEME => 'default', :CHOICE => 2) # Add in any available loadable themes. -TkPackage.names.find_all{|n| n =~ /^tile::theme::/}.each{|pkg| +TkPackage.names.find_all{|n| n =~ /^(tile|ttk)::theme::/}.each{|pkg| name = pkg.split('::')[-1] unless $THEMELIST.assoc(name) $THEMELIST << [name, Tk.tk_call('string', 'totitle', name)] @@ -66,7 +72,8 @@ TkPackage.names.find_all{|n| n =~ /^tile::theme::/}.each{|pkg| $RUBY_THEMELIST = [] begin load(File.join(demodir, 'themes', 'kroc.rb'), true) -rescue +rescue => e +raise e $RUBY_THEMELIST << ['kroc-rb', 'Kroc (by Ruby)', false] else $RUBY_THEMELIST << ['kroc-rb', 'Kroc (by Ruby)', true] @@ -79,8 +86,8 @@ def makeThemeControl(parent) :variable=>$V.ref(:THEME), :command=>proc{setTheme(theme)}) b.grid(:sticky=>:ew) - unless (TkPackage.names.find{|n| n == "tile::theme::#{theme}"}) - b.state(:disabled) + unless (TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/}) + b.ttk_state(:disabled) end } $RUBY_THEMELIST.each{|theme, name, available| @@ -88,7 +95,7 @@ def makeThemeControl(parent) :variable=>$V.ref(:THEME), :command=>proc{setTheme(theme)}) b.grid(:sticky=>:ew) - b.state(:disabled) unless available + b.ttk_state(:disabled) unless available } c end @@ -98,7 +105,7 @@ def makeThemeMenu(parent) $THEMELIST.each{|theme, name| m.add(:radiobutton, :label=>name, :variable=>$V.ref(:THEME), :value=>theme, :command=>proc{setTheme(theme)}) - unless (TkPackage.names.find{|n| n == "tile::theme::#{theme}"}) + unless (TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/}) m.entryconfigure(:end, :state=>:disabled) end } @@ -111,8 +118,10 @@ def makeThemeMenu(parent) end def setTheme(theme) - if (TkPackage.names.find{|n| n == "tile::theme::#{theme}"}) - TkPackage.require("tile::theme::#{theme}") + if (pkg = TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/}) + unless Tk::Tile::Style.theme_names.find{|n| n == theme} + TkPackage.require(pkg) + end end Tk::Tile::Style.theme_use(theme) end @@ -675,7 +684,7 @@ values = %w(list abc def ghi jkl mno pqr stu vwx yz) combo, :values=>values, :textvariable=>$V.ref(:COMBO)) cb.pack(:side=>:top, :padx=>2, :pady=>2, :expand=>false, :fill=>:x) if i == 1 - cb.state :readonly + cb.ttk_state :readonly begin cb.current = 3 # ignore if unsupported (tile0.4) rescue @@ -922,11 +931,11 @@ end def updateStates $states_list.each{|st| begin - $State[st] = $Widget.window.instate(st) + $State[st] = $Widget.window.ttk_instate(st) rescue - $states_btns[st].state('disabled') + $states_btns[st].ttk_state('disabled') else - $states_btns[st].state('!disabled') + $states_btns[st].ttk_state('!disabled') end } end @@ -934,9 +943,9 @@ end def changeState(st) if $Widget.value != '' if $State.bool_element(st) - $Widget.window.state(st) + $Widget.window.ttk_state(st) else - $Widget.window.state("!#{st}") + $Widget.window.ttk_state("!#{st}") end end end diff --git a/ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tcl b/ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tcl index 19ddda7c7..4facac70d 100644 --- a/ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tcl +++ b/ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tcl @@ -1,6 +1,6 @@ # Package index for tile demo pixmap themes. if {[file isdirectory [file join $dir blue]]} { - package ifneeded tile::theme::blue 0.0.1 \ + package ifneeded tile::theme::blue 0.7 \ [list source [file join $dir blue.tcl]] } diff --git a/ext/tk/sample/tkextlib/tile/themes/kroc.rb b/ext/tk/sample/tkextlib/tile/themes/kroc.rb index f67ce7a89..27006d847 100644 --- a/ext/tk/sample/tkextlib/tile/themes/kroc.rb +++ b/ext/tk/sample/tkextlib/tile/themes/kroc.rb @@ -95,8 +95,35 @@ def kroc_rb_settings # # Elements: # - if TkPackage.vcompare(Tk::Tile.package_version, '0.5') >= 0 + if Tk::Tile::TILE_SPEC_VERSION_ID >= 8 + Tk::Tile::Style.element_create('Button.button', + :image, + [ $images['button-n'], + :pressed, $images['button-p'], + :active, $images['button-h'], + ], :border=>3, :sticky=>:ew) + + Tk::Tile::Style.element_create('Checkbutton.indicator', + :image, + [ $images['check-nu'], + [:pressed, :selected],$images['check-nc'], + :pressed, $images['check-nu'], + [:active, :selected], $images['check-hc'], + :active, $images['check-hu'], + :selected, $images['check-nc'], + ], :sticky=>:w) + Tk::Tile::Style.element_create('Radiobutton.indicator', + :image, + [ $images['radio-nu'], + [:pressed,:selected],$images['radio-nc'], + :pressed, $images['radio-nu'], + [:active,:selected], $images['radio-hc'], + :active, $images['radio-hu'], + :selected, $images['radio-nc'], + ], :sticky=>:w) + + elsif TkPackage.vcompare(Tk::Tile.package_version, '0.5') >= 0 Tk::Tile::Style.element_create('Button.button', :image, $images['button-n'], :map=>[ @@ -125,7 +152,6 @@ def kroc_rb_settings ], :sticky=>:w) else # tile 0.4 or earlier - Tk::Tile::Style.element_create('Button.button', :pixmap, :images=>[ :pressed, $images['button-p'], diff --git a/ext/tk/sample/tkextlib/tile/toolbutton.tcl b/ext/tk/sample/tkextlib/tile/toolbutton.tcl index 2656fff6d..4e08034e3 100644 --- a/ext/tk/sample/tkextlib/tile/toolbutton.tcl +++ b/ext/tk/sample/tkextlib/tile/toolbutton.tcl @@ -4,18 +4,6 @@ # Demonstration of custom widget styles. # -set tile_ver [package require tile] -if {[package vcompare $tile_ver 0.8] >= 0} { - set style ::ttk::style -} { - set style style -} -if {[package vcompare $tile_ver 0.7] >= 0} { - set conf_subcmd configure -} { - set conf_subcmd default -} - # # ~ BACKGROUND # @@ -54,8 +42,7 @@ if {[package vcompare $tile_ver 0.7] >= 0} { # style; see demo.tcl.) # -#$style theme settings "step" { -$style theme settings "alt" { +style theme settings "step" { # # First, we use [style layout] to define what elements to @@ -64,7 +51,7 @@ $style theme settings "alt" { # and a label. (See also the TScrollbar layout definition # in demos/blue.tcl for a more complicated layout spec.) # - $style layout Toolbutton { + style layout Toolbutton { Toolbutton.background Toolbutton.border -children { Toolbutton.padding -children { @@ -81,7 +68,7 @@ $style theme settings "alt" { # For many options (like -background), the defaults # inherited from the parent style are sufficient. # - $style $conf_subcmd Toolbutton -width 0 -padding 1 -relief flat -borderwidth 2 + style default Toolbutton -width 0 -padding 1 -relief flat -borderwidth 2 # # Finally, use [style map] to specify state-specific @@ -91,7 +78,7 @@ $style theme settings "alt" { # over the widget). Each state-value pair is checked # in order, and the first matching state takes precedence. # - $style map Toolbutton -relief { + style map Toolbutton -relief { disabled flat selected sunken pressed sunken @@ -106,19 +93,19 @@ $style theme settings "alt" { # design decisions from an aesthetic standpoint.) # if {![catch {package require tile::theme::blue}]} { -$style theme settings "blue" { +style theme settings "blue" { # # Default values: # - $style $conf_subcmd Toolbutton \ + style default Toolbutton \ -width 0 -relief flat -borderwidth 2 \ -background #6699CC -foreground #000000 ; # # Configure state-specific values for -relief, as before: # - $style map Toolbutton -relief { + style map Toolbutton -relief { disabled flat selected sunken pressed sunken @@ -129,8 +116,8 @@ $style theme settings "blue" { # Adjust the -padding at the same time, to enhance # the raised/sunken illusion: # - $style $conf_subcmd Toolbutton -padding 4 - $style map Toolbutton -padding { + style default Toolbutton -padding 4 + style map Toolbutton -padding { disabled {4} selected {6 6 2 2} pressed {6 6 2 2} @@ -141,7 +128,7 @@ $style theme settings "blue" { # ... and change the foreground and background colors # when the mouse cursor is over the widget: # - $style map Toolbutton -background { + style map Toolbutton -background { active #008800 } -foreground { active #FFFFFF diff --git a/ext/tk/sample/tkrttimer.rb b/ext/tk/sample/tkrttimer.rb index 531f4a8d5..0abd4ecbd 100644 --- a/ext/tk/sample/tkrttimer.rb +++ b/ext/tk/sample/tkrttimer.rb @@ -17,8 +17,17 @@ TkLabel.new(f2, :text=>'use TkRTTimer class').pack label2 = TkLabel.new(:parent=>f2, :relief=>:raised, :width=>10).pack(:fill=>:both) -TkLabel.new(:text=>'Interval setting of each timer is 10 ms.', - :padx=>10, :pady=>5).pack +TkLabel.new(:padx=>10, :pady=>5, :justify=>'left', :text=><<EOT).pack +Interval setting of each timer object is 10 ms. +Each timer object counts up the value on each callback +(the value is not the clock data). +The count of the TkTimer object is delayed by execution +time of callbacks and inaccuracy of interval. +On the other hand, the count of the TkRTTimer object is +not delayed. Its callback interval is not accurate too. +But it can compute error correction about the time when +a callback should start. +EOT # define the procedure repeated by the TkTimer object tick = proc{|aobj| #<== TkTimer object diff --git a/ext/tk/sample/tksleep_sample.rb b/ext/tk/sample/tksleep_sample.rb new file mode 100644 index 000000000..23f6eca54 --- /dev/null +++ b/ext/tk/sample/tksleep_sample.rb @@ -0,0 +1,29 @@ +require 'tk' + +v = TkVariable.new(0) +l = TkLabel.new(:textvariable=>v).pack(:pady=>[1, 10]) + +a = TkButton.new(:text=>"button A :: proc{p ['AAA', v.value]}").pack(:fill=>:x, :pady=>[1, 15], :padx=>15) +a.command{p ['AAA', v.value]} + +TkLabel.new(:text=>'Callback of the button B returns LIFO order').pack +b = TkButton.new(:text=>"button B :: proc{n = v.value; p ['B:start', n]; Tk.sleep(10000); p ['B:end', n]}").pack(:fill=>:x, :pady=>[1, 15], :padx=>15) +b.command{n = v.value; p ['B:start', n]; Tk.sleep(10000); p ['B:end', n]} + +TkLabel.new(:text=>'Callback of the button C returns FIFO order').pack +c = TkButton.new(:text=>"button C :: proc{n = v.value; Thread.new{p ['C:start', n]; Tk.sleep(10000); p ['C:end', n]}}").pack(:fill=>:x, :pady=>[1, 15], :padx=>15) +c.command{n = v.value; Thread.new{p ['C:start', n]; Tk.sleep(10000); p ['C:end', n]}} + +TkLabel.new(:text=>'Callback of the button D blocks eventloop (no respond to event)').pack +d = TkButton.new(:text=>"button D :: proc{n = v.value; p ['D:start', n]; sleep(10); p ['D:end', n]}").pack(:fill=>:x, :pady=>[1,15], :padx=>15) +d.command{n = v.value; p ['D:start', n]; sleep(10); p ['D:end', n]} + +TkLabel.new(:text=>'Callback of the button E is another way to avoid eventloop blocking').pack +e = TkButton.new(:text=>"button E :: proc{n = v.value; Thread.new{p ['D:start', n]; sleep(10); p ['D:end', n]}}").pack(:fill=>:x, :pady=>[1,15], :padx=>15) +e.command{n = v.value; Thread.new{p ['D:start', n]; sleep(10); p ['D:end', n]}} + +TkButton.new(:text=>'QUIT', :command=>proc{exit}).pack + +TkTimer.new(500, -1){v.numeric += 1}.start + +Tk.mainloop diff --git a/ext/tk/sample/ttk_wrapper.rb b/ext/tk/sample/ttk_wrapper.rb new file mode 100644 index 000000000..30ae0ece5 --- /dev/null +++ b/ext/tk/sample/ttk_wrapper.rb @@ -0,0 +1,154 @@ +#!/usr/bin/env ruby +# +# ttk_wrapper.rb -- use Ttk widgets as default on old Ruby/Tk scripts +# +# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) +# +version = '0.1' +# +########################################################################## +# parse commandline arguments +########################################################################## +require 'optparse' +opt = OptionParser.new("Usage: #{$0} [options] rubytk_script" << "\n " << + "Ruby/Tk script wrapper. Use Ttk widgets as default.") +opt.version = version + +OPTS = {} +OPTS[:themedir] = [] +OPTS[:rb_theme] = [] +OPTS[:theme] = 'default' + +opt.on('-l', '--list', 'list available theme names'){|v| OPTS[:list] = true} +opt.on('-t', '--theme theme', 'theme name'){|v| OPTS[:theme] = v} +opt.on('-d', '--themedir themes_dir', 'directory of theme definitions'){|v| + OPTS[:themedir] << v +} +opt.on('-r', '--rubytheme rb_theme', 'theme definition file (ruby script)'){|v| + OPTS[:rb_theme] << v +} +opt.on('-v', '--verbose', 'print verbose messages'){|v| OPTS[:verbose] = true} + +opt.parse!(ARGV) + + +########################################################################## +# load Ttk (Tile) extension +########################################################################## +require 'tk' + +begin + require 'tkextlib/tile' + Tk.default_widget_set = :Ttk +rescue LoadError + if OPTS[:verbose] + print "warning: fail to load 'Ttk' extension. use standard widgets.\n" + end +end + +if OPTS[:verbose] + print "current default widget set is '#{Tk.default_widget_set}'\n" +end + + +########################################################################## +# use themes defined on the demo of Ttk (Tile) extension +########################################################################## +demodir = File.dirname(__FILE__) +demo_themesdir = File.expand_path(File.join(demodir, 'tkextlib', 'tile', 'themes')) + +Tk::AUTO_PATH.lappend(*OPTS[:themedir]) unless OPTS[:themedir].empty? +Tk::AUTO_PATH.lappend('.', demodir, demo_themesdir) + +OPTS[:themedir] << demo_themesdir +print "theme-dirs: #{OPTS[:themedir].inspect}\n" if OPTS[:verbose] + +OPTS[:themedir].each{|themesdir| + if File.directory?(themesdir) + Dir.foreach(themesdir){|name| + next if name == '.' || name == '..' + path = File.join(themesdir, name) + Tk::AUTO_PATH.lappend(path) if File.directory?(path) + } + end +} + +# This forces an update of the available packages list. It's required +# for package names to find the themes in demos/themes/*.tcl +Tk.ip_eval("#{TkPackage.unknown_proc} Tcl #{TkPackage.provide('Tcl')}") + +# load themes written in Ruby. +themes_by_ruby = [File.join(demo_themesdir, 'kroc.rb')] +themes_by_ruby.concat OPTS[:rb_theme] +print "ruby-themes: #{themes_by_ruby.inspect}\n" if OPTS[:verbose] + +themes_by_ruby.each{|f| + begin + load(f, true) + rescue LoadError + print "fail to load \"#{f}\"\n" if OPTS[:verbose] + end +} + + +########################################################################## +# define Tcl/Tk procedures for compatibility. +# those are required when want to use themes included +# in "sample/tkextlib/tile/demo.rb". +########################################################################## +Tk::Tile.__define_LoadImages_proc_for_compatibility__! +Tk::Tile::Style.__define_wrapper_proc_for_compatibility__! + + +########################################################################## +# ignore unsupported options of Ttk widgets +########################################################################## +TkConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__! true +TkItemConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__! true + + +########################################################################## +# define utility method +########################################################################## +def setTheme(theme) + unless Tk::Tile::Style.theme_names.find{|n| n == theme} + if (pkg = TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/}) + TkPackage.require(pkg) + end + end + Tk::Tile::Style.theme_use(theme) +end + + +########################################################################## +# make theme name list +########################################################################## +ThemesList = Tk::Tile::Style.theme_names +TkPackage.names.find_all{|n| n =~ /^(tile|ttk)::theme::/}.each{|pkg| + ThemesList << pkg.split('::')[-1] +} +ThemesList.uniq! + + +########################################################################## +# set theme of widget style +########################################################################## +if OPTS[:list] || OPTS[:verbose] + print "supported theme names: #{ThemesList}\n" + exit if OPTS[:list] && ARGV.empty? +end +print "use theme: \"#{OPTS[:theme]}\"\n" if OPTS[:theme] && OPTS[:verbose] +setTheme(OPTS[:theme]) if OPTS[:theme] + + +########################################################################## +# load script +########################################################################## +if (script = File.expand_path(ARGV.shift)) + print "load script \"#{script}\"\n" if OPTS[:verbose] + load(script) +else + print "Error: no script is given.\n" + print opt.help + exit(1) +end diff --git a/ext/tk/stubs.c b/ext/tk/stubs.c index d0aaf61f3..6d3b330f0 100644 --- a/ext/tk/stubs.c +++ b/ext/tk/stubs.c @@ -1,5 +1,11 @@ +/************************************************ + + stubs.c - Tcl/Tk stubs support + +************************************************/ + +#include "ruby.h" #include "stubs.h" -#include "ruby/ruby.h" #include <tcl.h> #include <tk.h> @@ -86,7 +92,12 @@ static DL_HANDLE tcl_dll = (DL_HANDLE)0; static DL_HANDLE tk_dll = (DL_HANDLE)0; int +#ifdef RUBY_VM ruby_open_tcl_dll(char *appname) +#else +ruby_open_tcl_dll(appname) + char *appname; +#endif { void (*p_Tcl_FindExecutable)(const char *); int n; @@ -168,7 +179,12 @@ ruby_open_tk_dll() } int +#ifdef RUBY_VM ruby_open_tcltk_dll(char *appname) +#else +ruby_open_tcltk_dll(appname) + char *appname; +#endif { return( ruby_open_tcl_dll(appname) || ruby_open_tk_dll() ); } @@ -187,7 +203,12 @@ tk_stubs_init_p() Tcl_Interp * +#ifdef RUBY_VM ruby_tcl_create_ip_and_stubs_init(int *st) +#else +ruby_tcl_create_ip_and_stubs_init(st) + int *st; +#endif { Tcl_Interp *tcl_ip; @@ -269,7 +290,12 @@ ruby_tcl_stubs_init() } int +#ifdef RUBY_VM ruby_tk_stubs_init(Tcl_Interp *tcl_ip) +#else +ruby_tk_stubs_init(tcl_ip) + Tcl_Interp *tcl_ip; +#endif { Tcl_ResetResult(tcl_ip); @@ -304,7 +330,12 @@ ruby_tk_stubs_init(Tcl_Interp *tcl_ip) } int +#ifdef RUBY_VM ruby_tk_stubs_safeinit(Tcl_Interp *tcl_ip) +#else +ruby_tk_stubs_safeinit(tcl_ip) + Tcl_Interp *tcl_ip; +#endif { Tcl_ResetResult(tcl_ip); @@ -390,7 +421,12 @@ static int open_tcl_dll = 0; static int call_tk_stubs_init = 0; int +#ifdef RUBY_VM ruby_open_tcl_dll(char *appname) +#else +ruby_open_tcl_dll(appname) + char *appname; +#endif { if (appname) { Tcl_FindExecutable(appname); @@ -402,7 +438,8 @@ ruby_open_tcl_dll(char *appname) return TCLTK_STUBS_OK; } -int ruby_open_tk_dll() +int +ruby_open_tk_dll() { if (!open_tcl_dll) { /* ruby_open_tcl_dll(RSTRING_PTR(rb_argv0)); */ @@ -412,7 +449,13 @@ int ruby_open_tk_dll() return TCLTK_STUBS_OK; } -int ruby_open_tcltk_dll(char *appname) +int +#ifdef RUBY_VM +ruby_open_tcltk_dll(char *appname) +#else +ruby_open_tcltk_dll(appname) + char *appname; +#endif { return( ruby_open_tcl_dll(appname) || ruby_open_tk_dll() ); } @@ -430,7 +473,12 @@ tk_stubs_init_p() } Tcl_Interp * +#ifdef RUBY_VM ruby_tcl_create_ip_and_stubs_init(int *st) +#else +ruby_tcl_create_ip_and_stubs_init(st) + int *st; +#endif { Tcl_Interp *tcl_ip; @@ -458,7 +506,12 @@ ruby_tcl_stubs_init() } int +#ifdef RUBY_VM ruby_tk_stubs_init(Tcl_Interp *tcl_ip) +#else +ruby_tk_stubs_init(tcl_ip) + Tcl_Interp *tcl_ip; +#endif { if (Tk_Init(tcl_ip) == TCL_ERROR) return FAIL_Tk_Init; @@ -474,7 +527,12 @@ ruby_tk_stubs_init(Tcl_Interp *tcl_ip) } int +#ifdef RUBY_VM ruby_tk_stubs_safeinit(Tcl_Interp *tcl_ip) +#else +ruby_tk_stubs_safeinit(tcl_ip) + Tcl_Interp *tcl_ip; +#endif { #if TCL_MAJOR_VERSION >= 8 if (Tk_SafeInit(tcl_ip) == TCL_ERROR) diff --git a/ext/tk/tcltklib.c b/ext/tk/tcltklib.c index df70e67c9..18e0fd76f 100644 --- a/ext/tk/tcltklib.c +++ b/ext/tk/tcltklib.c @@ -4,10 +4,20 @@ * Oct. 24, 1997 Y. Matsumoto */ -#define TCLTKLIB_RELEASE_DATE "2007-12-21" +#define TCLTKLIB_RELEASE_DATE "2008-03-29" -#include "ruby/ruby.h" +#include "ruby.h" + +#ifdef RUBY_VM +/* #include "ruby/ruby.h" */ #include "ruby/signal.h" +#include "ruby/encoding.h" +#else +/* #include "ruby.h" */ +#include "rubysig.h" +#include "version.h" +#endif + #undef EXTERN /* avoid conflict with tcl.h of tcl8.2 or before */ #include <stdio.h> #ifdef HAVE_STDARG_PROTOTYPES @@ -29,6 +39,24 @@ #define TCL_FINAL_RELEASE 2 #endif +static struct { + int major; + int minor; + int patchlevel; + int type; +} tcltk_version = {0, 0, 0, 0}; + +static void +set_tcltk_version() +{ + if (tcltk_version.major) return; + + Tcl_GetVersion(&(tcltk_version.major), + &(tcltk_version.minor), + &(tcltk_version.patchlevel), + &(tcltk_version.type)); +} + #if TCL_MAJOR_VERSION >= 8 # ifndef CONST84 # if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 4 /* Tcl8.0.x -- 8.4b1 */ @@ -82,6 +110,26 @@ static void ip_finalize _((Tcl_Interp*)); static int at_exit = 0; +#ifdef RUBY_VM +static VALUE cRubyEncoding; + +/* encoding */ +static int ENCODING_INDEX_UTF8; +static int ENCODING_INDEX_BINARY; +#endif +static VALUE ENCODING_NAME_UTF8; +static VALUE ENCODING_NAME_BINARY; + +static VALUE create_dummy_encoding_for_tk_core _((VALUE, VALUE, VALUE)); +static VALUE create_dummy_encoding_for_tk _((VALUE, VALUE)); +static int update_encoding_table _((VALUE, VALUE, VALUE)); +static VALUE encoding_table_get_name_core _((VALUE, VALUE, VALUE)); +static VALUE encoding_table_get_obj_core _((VALUE, VALUE, VALUE)); +static VALUE encoding_table_get_name _((VALUE, VALUE)); +static VALUE encoding_table_get_obj _((VALUE, VALUE)); +static VALUE create_encoding_table _((VALUE)); +static VALUE ip_get_encoding_table _((VALUE)); + /* for callback break & continue */ static VALUE eTkCallbackReturn; @@ -100,6 +148,9 @@ static VALUE tcltkip_class; static ID ID_at_enc; static ID ID_at_interp; +static ID ID_encoding_name; +static ID ID_encoding_table; + static ID ID_stop_p; static ID ID_alive_p; static ID ID_kill; @@ -123,9 +174,30 @@ static VALUE ip_invoke _((int, VALUE*, VALUE)); static VALUE tk_funcall _((VALUE(), int, VALUE*, VALUE)); +/* Tcl's object type */ +#if TCL_MAJOR_VERSION >= 8 +static char *Tcl_ObjTypeName_ByteArray = "bytearray"; +static Tcl_ObjType *Tcl_ObjType_ByteArray; + +static char *Tcl_ObjTypeName_String = "string"; +static Tcl_ObjType *Tcl_ObjType_String; + +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) +#define IS_TCL_BYTEARRAY(obj) ((obj)->typePtr == Tcl_ObjType_ByteArray) +#define IS_TCL_STRING(obj) ((obj)->typePtr == Tcl_ObjType_String) +#define IS_TCL_VALID_STRING(obj) ((obj)->bytes != (char*)NULL) +#endif +#endif + /* safe Tcl_Eval and Tcl_GlobalEval */ static int +#ifdef RUBY_VM tcl_eval(Tcl_Interp *interp, const char *cmd) +#else +tcl_eval(interp, cmd) + Tcl_Interp *interp; + const char *cmd; /* don't have to be writable */ +#endif { char *buf = strdup(cmd); int ret; @@ -140,7 +212,13 @@ tcl_eval(Tcl_Interp *interp, const char *cmd) #define Tcl_Eval tcl_eval static int +#ifdef RUBY_VM tcl_global_eval(Tcl_Interp *interp, const char *cmd) +#else +tcl_global_eval(interp, cmd) + Tcl_Interp *interp; + const char *cmd; /* don't have to be writable */ +#endif { char *buf = strdup(cmd); int ret; @@ -311,13 +389,24 @@ call_queue_mark(struct call_queue *q) static VALUE eventloop_thread; +#ifdef RUBY_VM +Tcl_ThreadId tk_eventloop_thread_id; /* native thread ID of Tcl interpreter */ +#endif static VALUE eventloop_stack; static int window_event_mode = ~(TCL_WINDOW_EVENTS | TCL_IDLE_EVENTS); static VALUE watchdog_thread; Tcl_Interp *current_interp; - + +/* thread control strategy */ +#define CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE 0 +#define USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0 +#define DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 1 + +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE +static int have_rb_thread_waited_for_value = 0; +#endif /* * 'event_loop_max' is a maximum events which the eventloop processes in one @@ -326,12 +415,27 @@ Tcl_Interp *current_interp; * 'timer_tick' is a limit of one term of thread scheduling. * If 'timer_tick' == 0, then not use the timer for thread scheduling. */ -#define DEFAULT_EVENT_LOOP_MAX 800/*counts*/ -#define DEFAULT_NO_EVENT_TICK 10/*counts*/ -#define DEFAULT_NO_EVENT_WAIT 20/*milliseconds ( 1 -- 999 ) */ -#define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */ -#define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */ -#define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */ +#ifdef RUBY_VM +#define DEFAULT_EVENT_LOOP_MAX 800/*counts*/ +#define DEFAULT_NO_EVENT_TICK 10/*counts*/ +#define DEFAULT_NO_EVENT_WAIT 10/*milliseconds ( 1 -- 999 ) */ +#define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */ +#define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */ +#define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */ +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE +#define DEFAULT_HAS_WAIT_THREAD_TICK 50/*counts*/ +#endif +#else /* ! RUBY_VM */ +#define DEFAULT_EVENT_LOOP_MAX 800/*counts*/ +#define DEFAULT_NO_EVENT_TICK 10/*counts*/ +#define DEFAULT_NO_EVENT_WAIT 20/*milliseconds ( 1 -- 999 ) */ +#define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */ +#define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */ +#define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */ +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE +#define DEFAULT_HAS_WAIT_THREAD_TICK 50/*counts*/ +#endif +#endif static int event_loop_max = DEFAULT_EVENT_LOOP_MAX; static int no_event_tick = DEFAULT_NO_EVENT_TICK; @@ -339,6 +443,9 @@ static int no_event_wait = DEFAULT_NO_EVENT_WAIT; static int timer_tick = DEFAULT_TIMER_TICK; static int req_timer_tick = DEFAULT_TIMER_TICK; static int run_timer_flag = 0; +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE +static int has_wait_thread_tick = DEFAULT_HAS_WAIT_THREAD_TICK; +#endif static int event_loop_wait_event = 0; static int event_loop_abort_on_exc = 1; @@ -567,7 +674,7 @@ struct tcltkip { Tcl_Namespace *default_ns; /* default namespace */ #endif #ifdef RUBY_VM - Tcl_ThreadId tk_thread_id; /* default namespace */ + Tcl_ThreadId tk_thread_id; /* native thread ID of Tcl interpreter */ #endif int has_orig_exit; /* has original 'exit' command ? */ Tcl_CmdInfo orig_exit_info; /* command info of original 'exit' command */ @@ -604,9 +711,9 @@ deleted_ip(ptr) #endif ) { DUMP1("ip is deleted"); - return Qtrue; + return 1; } - return Qfalse; + return 0; } /* increment/decrement reference count of tcltkip */ @@ -770,6 +877,7 @@ tcltkip_init_tk(interp) /* treat excetiopn on Tcl side */ static VALUE rbtk_pending_exception; static int rbtk_eventloop_depth = 0; +static int rbtk_internal_eventloop_handler = 0; static int @@ -779,7 +887,9 @@ pending_exception_check0() if (!NIL_P(exc) && rb_obj_is_kind_of(exc, rb_eException)) { DUMP1("find a pending exception"); - if (rbtk_eventloop_depth > 0) { + if (rbtk_eventloop_depth > 0 + || rbtk_internal_eventloop_handler > 0 + ) { return 1; /* pending */ } else { rbtk_pending_exception = Qnil; @@ -812,7 +922,9 @@ pending_exception_check1(thr_crit_bup, ptr) if (!NIL_P(exc) && rb_obj_is_kind_of(exc, rb_eException)) { DUMP1("find a pending exception"); - if (rbtk_eventloop_depth > 0) { + if (rbtk_eventloop_depth > 0 + || rbtk_internal_eventloop_handler > 0 + ) { return 1; /* pending */ } else { rbtk_pending_exception = Qnil; @@ -870,8 +982,11 @@ call_original_exit(ptr, state) if (info->isNativeObjectProc) { Tcl_Obj **argv; - // argv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, 3); /* XXXXXXXXXX */ + /* argv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, 3); */ /* XXXXXXXXXX */ argv = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj *) * 3); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ +#endif argv[0] = Tcl_NewStringObj("exit", 4); argv[1] = state_obj; argv[2] = (Tcl_Obj *)NULL; @@ -879,13 +994,24 @@ call_original_exit(ptr, state) ptr->return_value = (*(info->objProc))(info->objClientData, ptr->ip, 2, argv); - free(argv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + /* free(argv); */ + ckfree((char*)argv); +#endif } else { /* string interface */ char **argv; - //argv = (char **)ALLOC_N(char *, 3); /* XXXXXXXXXX */ - argv = (char **)ckalloc(sizeof(char *) * 3); + /* argv = (char **)ALLOC_N(char *, 3); */ /* XXXXXXXXXX */ + argv = (char **)ckalloc(sizeof(char *) * 3); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ +#endif argv[0] = "exit"; /* argv[1] = Tcl_GetString(state_obj); */ argv[1] = Tcl_GetStringFromObj(state_obj, (int*)NULL); @@ -894,7 +1020,15 @@ call_original_exit(ptr, state) ptr->return_value = (*(info->proc))(info->clientData, ptr->ip, 2, (CONST84 char **)argv); - free(argv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + /* free(argv); */ + ckfree((char*)argv); +#endif } Tcl_DecrRefCount(state_obj); @@ -903,7 +1037,11 @@ call_original_exit(ptr, state) { /* string interface */ char **argv; - argv = (char **)ALLOC_N(char *, 3); + /* argv = (char **)ALLOC_N(char *, 3); */ + argv = (char **)ckalloc(sizeof(char *) * 3); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ +#endif argv[0] = "exit"; argv[1] = RSTRING_PTR(rb_fix2str(INT2NUM(state), 10)); argv[2] = (char *)NULL; @@ -911,7 +1049,15 @@ call_original_exit(ptr, state) ptr->return_value = (*(info->proc))(info->clientData, ptr->ip, 2, argv); - free(argv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + /* free(argv); */ + ckfree(argv); +#endif } #endif @@ -954,6 +1100,21 @@ _timer_for_tcl(clientData) /* tick_counter += event_loop_max; */ } +#ifdef RUBY_VM +#if USE_TOGGLE_WINDOW_MODE_FOR_IDLE +static int +toggle_eventloop_window_mode_for_idle() +{ + if (window_event_mode & TCL_IDLE_EVENTS) { + window_event_mode &= ~TCL_IDLE_EVENTS; + return 1; + } else { + window_event_mode |= TCL_IDLE_EVENTS; + return 0; + } +} +#endif +#endif static VALUE set_eventloop_window_mode(self, mode) @@ -1262,8 +1423,10 @@ ip_evloop_abort_on_exc_set(self, val) } static VALUE -lib_num_of_mainwindows(self) +lib_num_of_mainwindows_core(self, argc, argv) VALUE self; + int argc; /* dummy */ + VALUE *argv; /* dummy */ { if (tk_stubs_init_p()) { return INT2FIX(Tk_GetNumMainWindows()); @@ -1272,7 +1435,37 @@ lib_num_of_mainwindows(self) } } +static VALUE +lib_num_of_mainwindows(self) + VALUE self; +{ + return tk_funcall(lib_num_of_mainwindows_core, 0, (VALUE*)NULL, self); +} + + +#ifdef RUBY_VM /* Ruby 1.9+ !!! */ +static VALUE +call_DoOneEvent_core(flag_val) + VALUE flag_val; +{ + int flag; + + flag = FIX2INT(flag_val); + if (Tcl_DoOneEvent(flag)) { + return Qtrue; + } else { + return Qfalse; + } +} + +static VALUE +call_DoOneEvent(flag_val) + VALUE flag_val; +{ + return tk_funcall(call_DoOneEvent_core, 0, (VALUE*)NULL, flag_val); +} +#else /* Ruby 1.8- */ static VALUE call_DoOneEvent(flag_val) VALUE flag_val; @@ -1286,6 +1479,8 @@ call_DoOneEvent(flag_val) return Qfalse; } } +#endif + static VALUE eventloop_sleep(dummy) @@ -1296,29 +1491,78 @@ eventloop_sleep(dummy) t.tv_sec = (time_t)0; t.tv_usec = (time_t)(no_event_wait*1000.0); -#if 0 #ifdef HAVE_NATIVETHREAD +#ifdef RUBY_VM +#if 0 if (!ruby_native_thread_p()) { rb_bug("cross-thread violation on eventloop_sleep()"); } #endif +#else + if (!is_ruby_native_thread()) { + rb_bug("cross-thread violation on eventloop_sleep()"); + } +#endif #endif DUMP2("eventloop_sleep: rb_thread_wait_for() at thread : %lx", rb_thread_current()); rb_thread_wait_for(t); DUMP2("eventloop_sleep: finish at thread : %lx", rb_thread_current()); -#if 0 #ifdef HAVE_NATIVETHREAD +#ifdef RUBY_VM +#if 0 if (!ruby_native_thread_p()) { rb_bug("cross-thread violation on eventloop_sleep()"); } #endif +#else + if (!is_ruby_native_thread()) { + rb_bug("cross-thread violation on eventloop_sleep()"); + } +#endif #endif return Qnil; } +#define USE_EVLOOP_THREAD_ALONE_CHECK_FLAG 0 + +#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG +static int +get_thread_alone_check_flag() +{ +#ifdef RUBY_VM + return 0; +#else + set_tcltk_version(); + + if (tcltk_version.major < 8) { + /* Tcl/Tk 7.x */ + return 1; + } else if (tcltk_version.major == 8) { + if (tcltk_version.minor < 5) { + /* Tcl/Tk 8.0 - 8.4 */ + return 1; + } else if (tcltk_version.minor == 5) { + if (tcltk_version.type < TCL_FINAL_RELEASE) { + /* Tcl/Tk 8.5a? - 8.5b? */ + return 1; + } else { + /* Tcl/Tk 8.5.x */ + return 0; + } + } else { + /* Tcl/Tk 8.6 - 8.9 ?? */ + return 0; + } + } else { + /* Tcl/Tk 9+ ?? */ + return 0; + } +#endif +} +#endif static int lib_eventloop_core(check_root, update_flag, check_var, interp) @@ -1334,7 +1578,9 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) int thr_crit_bup; int status; int depth = rbtk_eventloop_depth; - +#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG + int thread_alone_check_flag = 1; +#endif if (update_flag) DUMP1("update loop start!!"); @@ -1353,9 +1599,14 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) timer_token = (Tcl_TimerToken)NULL; } +#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG + /* version check */ + thread_alone_check_flag = get_thread_alone_check_flag(); +#endif + for(;;) { -#ifdef RUBY_VM - if (0) { +#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG + if (thread_alone_check_flag && rb_thread_alone()) { #else if (rb_thread_alone()) { #endif @@ -1365,8 +1616,8 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) if (update_flag) { event_flag = update_flag | TCL_DONT_WAIT; /* for safety */ } else { - // event_flag = TCL_ALL_EVENTS; - event_flag = TCL_FILE_EVENTS | TCL_TIMER_EVENTS | TCL_DONT_WAIT; + event_flag = TCL_ALL_EVENTS; + /* event_flag = TCL_ALL_EVENTS | TCL_DONT_WAIT; */ } if (timer_tick == 0 && update_flag == 0) { @@ -1393,11 +1644,19 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) if (status) { switch (status) { case TAG_RAISE: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eException, "unknown exception"); } else { +#ifdef RUBY_VM rbtk_pending_exception = rb_errinfo(); +#else + rbtk_pending_exception = ruby_errinfo; +#endif if (!NIL_P(rbtk_pending_exception)) { if (rbtk_eventloop_depth == 0) { @@ -1412,10 +1671,18 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) break; case TAG_FATAL: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif rb_exc_raise(rb_exc_new2(rb_eFatal, "FATAL")); } else { +#ifdef RUBY_VM rb_exc_raise(rb_errinfo()); +#else + rb_exc_raise(ruby_errinfo); +#endif } } } @@ -1514,6 +1781,17 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) st = RTEST(rb_protect(call_DoOneEvent, INT2FIX(event_flag & window_event_mode), &status)); +#if USE_TOGGLE_WINDOW_MODE_FOR_IDLE + if (!st) { + if (toggle_eventloop_window_mode_for_idle()) { + /* idle-mode -> event-mode*/ + tick_counter = 0; + } else { + /* event-mode -> idle-mode */ + tick_counter = event_loop_max; + } + } +#endif } #else /* st = Tcl_DoOneEvent(event_flag); */ @@ -1523,12 +1801,20 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) if (status) { switch (status) { case TAG_RAISE: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eException, "unknown exception"); } else { +#ifdef RUBY_VM rbtk_pending_exception = rb_errinfo(); +#else + rbtk_pending_exception = ruby_errinfo; +#endif if (!NIL_P(rbtk_pending_exception)) { if (rbtk_eventloop_depth == 0) { @@ -1543,10 +1829,18 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) break; case TAG_FATAL: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif rb_exc_raise(rb_exc_new2(rb_eFatal, "FATAL")); } else { +#ifdef RUBY_VM rb_exc_raise(rb_errinfo()); +#else + rb_exc_raise(ruby_errinfo); +#endif } } } @@ -1579,6 +1873,13 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) return 0; } +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE + if (have_rb_thread_waited_for_value) { + tick_counter += no_event_tick; + have_rb_thread_waited_for_value = 0; + } +#endif + if (st) { tick_counter++; } else { @@ -1590,19 +1891,26 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) tick_counter += no_event_tick; /* rb_thread_wait_for(t); */ -#if 0 + rb_protect(eventloop_sleep, Qnil, &status); -#endif if (status) { switch (status) { case TAG_RAISE: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eException, "unknown exception"); } else { +#ifdef RUBY_VM rbtk_pending_exception = rb_errinfo(); +#else + rbtk_pending_exception = ruby_errinfo; +#endif if (!NIL_P(rbtk_pending_exception)) { if (rbtk_eventloop_depth == 0) { @@ -1617,11 +1925,19 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) break; case TAG_FATAL: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif rb_exc_raise(rb_exc_new2(rb_eFatal, "FATAL")); } else { +#ifdef RUBY_VM rb_exc_raise(rb_errinfo()); +#else + rb_exc_raise(ruby_errinfo); +#endif } } } @@ -1676,12 +1992,16 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) } } - DUMP1("thread scheduling"); - rb_thread_schedule(); + DUMP1("thread scheduling"); + rb_thread_schedule(); } DUMP1("trap check & thread scheduling"); - if (update_flag == 0) ; // TODO: CHECK_INTS +#ifdef RUBY_VM + /* if (update_flag == 0) CHECK_INTS; */ /*XXXXXXXXXXXXX TODO !!!! */ +#else + if (update_flag == 0) CHECK_INTS; +#endif } return 1; @@ -1728,19 +2048,35 @@ lib_eventloop_main(args) switch (status) { case TAG_RAISE: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eException, "unknown exception"); } else { +#ifdef RUBY_VM rbtk_pending_exception = rb_errinfo(); +#else + rbtk_pending_exception = ruby_errinfo; +#endif } return Qnil; case TAG_FATAL: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL"); } else { +#ifdef RUBY_VM rbtk_pending_exception = rb_errinfo(); +#else + rbtk_pending_exception = ruby_errinfo; +#endif } return Qnil; } @@ -1764,6 +2100,7 @@ lib_eventloop_ensure(args) rb_thread_critical = ptr->thr_crit_bup; free(ptr); + /* ckfree((char*)ptr); */ return Qnil; } @@ -1793,9 +2130,16 @@ lib_eventloop_ensure(args) } } +#ifdef RUBY_VM + if (NIL_P(eventloop_thread)) { + tk_eventloop_thread_id = (Tcl_ThreadId) 0; + } +#endif + rb_thread_critical = ptr->thr_crit_bup; free(ptr); + /* ckfree((char*)ptr);*/ DUMP2("finish current eventloop %lx", current_evloop); return Qnil; @@ -1810,10 +2154,14 @@ lib_eventloop_launcher(check_root, update_flag, check_var, interp) { volatile VALUE parent_evloop = eventloop_thread; struct evloop_params *args = ALLOC(struct evloop_params); + /* struct evloop_params *args = (struct evloop_params *)ckalloc(sizeof(struct evloop_params)); */ tcl_stubs_check(); eventloop_thread = rb_thread_current(); +#ifdef RUBY_VM + tk_eventloop_thread_id = Tcl_GetCurrentThread(); +#endif if (parent_evloop == eventloop_thread) { DUMP2("eventloop: recursive call on %lx", parent_evloop); @@ -1964,6 +2312,9 @@ lib_watchdog_ensure(arg) VALUE arg; { eventloop_thread = Qnil; /* stop eventloops */ +#ifdef RUBY_VM + tk_eventloop_thread_id = (Tcl_ThreadId) 0; +#endif return Qnil; } @@ -1975,6 +2326,11 @@ lib_mainloop_watchdog(argc, argv, self) { VALUE check_rootwidget; +#ifdef RUBY_VM + rb_raise(rb_eNotImpError, + "eventloop_watchdog is not implemented on Ruby VM."); +#endif + if (rb_scan_args(argc, argv, "01", &check_rootwidget) == 0) { check_rootwidget = Qtrue; } else if (RTEST(check_rootwidget)) { @@ -2068,11 +2424,11 @@ lib_thread_callback(argc, argv, self) proc = rb_block_proc(); } - //q = (struct thread_call_proc_arg *)ALLOC(struct thread_call_proc_arg); - q = (struct thread_call_proc_arg *)ckalloc(sizeof(struct thread_call_proc_arg)); + q = (struct thread_call_proc_arg *)ALLOC(struct thread_call_proc_arg); + /* q = (struct thread_call_proc_arg *)ckalloc(sizeof(struct thread_call_proc_arg)); */ q->proc = proc; - //q->done = (int*)ALLOC(int); - q->done = (int*)ckalloc(sizeof(int)); + q->done = (int*)ALLOC(int); + /* q->done = (int*)ckalloc(sizeof(int)); */ *(q->done) = 0; /* create call-proc thread */ @@ -2091,16 +2447,23 @@ lib_thread_callback(argc, argv, self) ret = rb_protect(_thread_call_proc_value, th, &status); } - //free(q->done); - //free(q); - ckfree((char*)q->done); - ckfree((char*)q); + free(q->done); + free(q); + /* ckfree((char*)q->done); */ + /* ckfree((char*)q); */ if (NIL_P(rbtk_pending_exception)) { +#ifdef RUBY_VM /* return rb_errinfo(); */ if (status) { rb_exc_raise(rb_errinfo()); } +#else + /* return ruby_errinfo; */ + if (status) { + rb_exc_raise(ruby_errinfo); + } +#endif } else { VALUE exc = rbtk_pending_exception; rbtk_pending_exception = Qnil; @@ -2225,8 +2588,11 @@ ip_set_exc_message(interp, exc) } /* to avoid a garbled error message dialog */ - // buf = ALLOC_N(char, (RSTRING_LEN(msg))+1); - buf = ckalloc(sizeof(char)*((RSTRING_LEN(msg))+1)); + /* buf = ALLOC_N(char, (RSTRING(msg)->len)+1);*/ + /* memcpy(buf, RSTRING(msg)->ptr, RSTRING(msg)->len);*/ + /* buf[RSTRING(msg)->len] = 0; */ + buf = ALLOC_N(char, RSTRING_LEN(msg)+1); + /* buf = ckalloc(sizeof(char)*((RSTRING_LEN(msg))+1)); */ memcpy(buf, RSTRING_PTR(msg), RSTRING_LEN(msg)); buf[RSTRING_LEN(msg)] = 0; @@ -2237,8 +2603,8 @@ ip_set_exc_message(interp, exc) Tcl_AppendResult(interp, Tcl_DStringValue(&dstr), (char*)NULL); DUMP2("error message:%s", Tcl_DStringValue(&dstr)); Tcl_DStringFree(&dstr); - //free(buf); - ckfree(buf); + free(buf); + /* ckfree(buf); */ #else /* TCL_VERSION <= 8.0 */ Tcl_AppendResult(interp, RSTRING_PTR(msg), (char*)NULL); @@ -2307,58 +2673,104 @@ tcl_protect_core(interp, proc, data) /* should not raise exception */ goto error; error: str = rb_str_new2("LocalJumpError: "); +#ifdef RUBY_VM rb_str_append(str, rb_obj_as_string(rb_errinfo())); +#else + rb_str_append(str, rb_obj_as_string(ruby_errinfo)); +#endif exc = rb_exc_new3(type, str); break; case TAG_RETRY: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif DUMP1("rb_protect: retry"); exc = rb_exc_new2(eTkCallbackRetry, "retry jump error"); } else { +#ifdef RUBY_VM exc = rb_errinfo(); +#else + exc = ruby_errinfo; +#endif } break; case TAG_REDO: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif DUMP1("rb_protect: redo"); exc = rb_exc_new2(eTkCallbackRedo, "redo jump error"); } else { +#ifdef RUBY_VM exc = rb_errinfo(); +#else + exc = ruby_errinfo; +#endif } break; case TAG_RAISE: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif exc = rb_exc_new2(rb_eException, "unknown exception"); } else { +#ifdef RUBY_VM exc = rb_errinfo(); +#else + exc = ruby_errinfo; +#endif } break; case TAG_FATAL: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif exc = rb_exc_new2(rb_eFatal, "FATAL"); } else { +#ifdef RUBY_VM exc = rb_errinfo(); +#else + exc = ruby_errinfo; +#endif } break; case TAG_THROW: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif DUMP1("rb_protect: throw"); exc = rb_exc_new2(eTkCallbackThrow, "throw jump error"); } else { +#ifdef RUBY_VM exc = rb_errinfo(); +#else + exc = ruby_errinfo; +#endif } break; default: buf = ALLOC_N(char, 256); + /* buf = ckalloc(sizeof(char) * 256); */ sprintf(buf, "unknown loncaljmp status %d", status); exc = rb_exc_new2(rb_eException, buf); free(buf); + /* ckfree(buf); */ break; } @@ -2455,12 +2867,18 @@ tcl_protect(interp, proc, data) int old_trapflag = rb_trap_immediate; int code; -#if 0 #ifdef HAVE_NATIVETHREAD +#ifdef RUBY_VM +#if 0 if (!ruby_native_thread_p()) { rb_bug("cross-thread violation on tcl_protect()"); } #endif +#else + if (!is_ruby_native_thread()) { + rb_bug("cross-thread violation on tcl_protect()"); + } +#endif #endif rb_trap_immediate = 0; @@ -2523,6 +2941,7 @@ ip_ruby_eval(clientData, interp, argc, argv) str = Tcl_GetStringFromObj(argv[1], &len); arg = ALLOC_N(char, len + 1); + /* arg = ckalloc(sizeof(char) * (len + 1)); */ memcpy(arg, str, len); arg[len] = 0; @@ -2540,6 +2959,7 @@ ip_ruby_eval(clientData, interp, argc, argv) #if TCL_MAJOR_VERSION >= 8 free(arg); + /* ckfree(arg); */ #endif return code; @@ -2564,6 +2984,96 @@ ip_ruby_cmd_core(arg) return ret; } +#define SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER 1 + +static VALUE +ip_ruby_cmd_receiver_const_get(name) + char *name; +{ + volatile VALUE klass = rb_cObject; + char *head, *tail; + int state; + +#if SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER + klass = rb_eval_string_protect(name, &state); + if (state) { + return Qnil; + } else { + return klass; + } +#else + return rb_const_get(klass, rb_intern(name)); +#endif + + /* TODO!!!!!! */ + /* support nest of classes/modules */ + + /* return rb_eval_string(name); */ + /* return rb_eval_string_protect(name, &state); */ + +#if 0 /* doesn't work!! (fail to autoload?) */ + /* duplicate */ + head = name = strdup(name); + + /* has '::' at head ? */ + if (*head == ':') head += 2; + tail = head; + + /* search */ + while(*tail) { + if (*tail == ':') { + *tail = '\0'; + klass = rb_const_get(klass, rb_intern(head)); + tail += 2; + head = tail; + } else { + tail++; + } + } + + free(name); + return rb_const_get(klass, rb_intern(head)); +#endif +} + +static VALUE +ip_ruby_cmd_receiver_get(str) + char *str; +{ + volatile VALUE receiver; + volatile VALUE klass = rb_cObject; + int state; + + if (str[0] == ':' || ('A' <= str[0] && str[0] <= 'Z')) { + /* class | module | constant */ +#if SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER + receiver = ip_ruby_cmd_receiver_const_get(str); +#else + receiver = rb_protect(ip_ruby_cmd_receiver_const_get, (VALUE)str, &state); + if (state) return Qnil; +#endif + } else if (str[0] == '$') { + /* global variable */ + receiver = rb_gv_get(str); + } else { + /* global variable omitted '$' */ + char *buf; + int len; + + len = strlen(str); + buf = ALLOC_N(char, len + 2); + /* buf = ckalloc(sizeof(char) * (len + 2)); */ + buf[0] = '$'; + memcpy(buf + 1, str, len); + buf[len + 1] = 0; + receiver = rb_gv_get(buf); + free(buf); + /* ckfree(buf); */ + } + + return receiver; +} + /* ruby_cmd receiver method arg ... */ static int #if TCL_MAJOR_VERSION >= 8 @@ -2611,6 +3121,7 @@ ip_ruby_cmd(clientData, interp, argc, argv) /* allocate */ arg = ALLOC(struct cmd_body_arg); + /* arg = (struct cmd_body_arg *)ckalloc(sizeof(struct cmd_body_arg)); */ /* get arguments from Tcl objects */ thr_crit_bup = rb_thread_critical; @@ -2624,24 +3135,8 @@ ip_ruby_cmd(clientData, interp, argc, argv) str = argv[1]; #endif DUMP2("receiver:%s",str); - if (str[0] == ':' || ('A' <= str[0] && str[0] <= 'Z')) { - /* class | module | constant */ - receiver = rb_const_get(rb_cObject, rb_intern(str)); - } else if (str[0] == '$') { - /* global variable */ - receiver = rb_gv_get(str); - } else { - /* global variable omitted '$' */ - char *buf; - - len = strlen(str); - buf = ALLOC_N(char, len + 2); - buf[0] = '$'; - memcpy(buf + 1, str, len); - buf[len + 1] = 0; - receiver = rb_gv_get(buf); - free(buf); - } + /* receiver = rb_protect(ip_ruby_cmd_receiver_get, (VALUE)str, &code); */ + receiver = ip_ruby_cmd_receiver_get(str); if (NIL_P(receiver)) { #if 0 rb_raise(rb_eArgError, @@ -2666,14 +3161,26 @@ ip_ruby_cmd(clientData, interp, argc, argv) /* get args */ args = rb_ary_new2(argc - 2); +#ifdef RUBY_VM +#else + RARRAY(args)->len = 0; +#endif for(i = 3; i < argc; i++) { #if TCL_MAJOR_VERSION >= 8 str = Tcl_GetStringFromObj(argv[i], &len); DUMP2("arg:%s",str); +#ifdef RUBY_VM rb_ary_push(args, rb_tainted_str_new(str, len)); +#else + RARRAY(args)->ptr[RARRAY(args)->len++] = rb_tainted_str_new(str, len); +#endif #else /* TCL_MAJOR_VERSION < 8 */ DUMP2("arg:%s",argv[i]); +#ifdef RUBY_VM rb_ary_push(args, rb_tainted_str_new2(argv[i])); +#else + RARRAY(args)->ptr[RARRAY(args)->len++] = rb_tainted_str_new2(argv[i]); +#endif #endif } @@ -2688,6 +3195,7 @@ ip_ruby_cmd(clientData, interp, argc, argv) code = tcl_protect(interp, ip_ruby_cmd_core, (VALUE)arg); free(arg); + /* ckfree((char*)arg); */ return code; } @@ -2864,12 +3372,18 @@ ip_rbUpdateCommand(clientData, interp, objc, objv) "IP is deleted"); return TCL_ERROR; } -#if 0 #ifdef HAVE_NATIVETHREAD +#ifdef RUBY_VM +#if 0 if (!ruby_native_thread_p()) { rb_bug("cross-thread violation on ip_ruby_eval()"); } #endif +#else + if (!is_ruby_native_thread()) { + rb_bug("cross-thread violation on ip_ruby_eval()"); + } +#endif #endif if (objc == 1) { @@ -3013,10 +3527,16 @@ ip_rb_threadUpdateCommand(clientData, interp, objc, objv) "IP is deleted"); return TCL_ERROR; } -#if 0 #ifdef HAVE_NATIVETHREAD +#ifdef RUBY_VM +#if 0 if (!ruby_native_thread_p()) { - rb_bug("cross-thread violation on ip_ruby_eval()"); + rb_bug("cross-thread violation on ip_rb_threadUpdateCommand()"); + } +#endif +#else + if (!is_ruby_native_thread()) { + rb_bug("cross-thread violation on ip_rb_threadUpdateCommand()"); } #endif #endif @@ -3080,8 +3600,11 @@ ip_rb_threadUpdateCommand(clientData, interp, objc, objv) DUMP1("pass argument check"); - param = (struct th_update_param *)Tcl_Alloc(sizeof(struct th_update_param)); - Tcl_Preserve(param); + /* param = (struct th_update_param *)Tcl_Alloc(sizeof(struct th_update_param)); */ + param = (struct th_update_param *)ckalloc(sizeof(struct th_update_param)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)param); +#endif param->thread = current_thread; param->done = 0; @@ -3093,8 +3616,15 @@ ip_rb_threadUpdateCommand(clientData, interp, objc, objv) rb_thread_stop(); } - Tcl_Release(param); - Tcl_Free((char *)param); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif DUMP1("finish Ruby's 'thread_update'"); return TCL_OK; @@ -3192,10 +3722,16 @@ ip_rbVwaitCommand(clientData, interp, objc, objv) #endif Tcl_Preserve(interp); -#if 0 #ifdef HAVE_NATIVETHREAD +#ifdef RUBY_VM +#if 0 if (!ruby_native_thread_p()) { - rb_bug("cross-thread violation on ip_ruby_eval()"); + rb_bug("cross-thread violation on ip_rbVwaitCommand()"); + } +#endif +#else + if (!is_ruby_native_thread()) { + rb_bug("cross-thread violation on ip_rbVwaitCommand()"); } #endif #endif @@ -3588,6 +4124,7 @@ ip_rbTkWaitCommand(clientData, interp, objc, objv) thr_crit_bup = rb_thread_critical; rb_thread_critical = Qtrue; + /* This function works on the Tk eventloop thread only. */ if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { window = NULL; } else { @@ -3595,7 +4132,7 @@ ip_rbTkWaitCommand(clientData, interp, objc, objv) } if (window == NULL) { - Tcl_AppendResult(interp, "tkwait: ", + Tcl_AppendResult(interp, ": tkwait: ", "no main-window (not Tk application?)", (char*)NULL); rb_thread_critical = thr_crit_bup; @@ -3684,7 +4221,8 @@ ip_rbTkWaitCommand(clientData, interp, objc, objv) case TKWAIT_WINDOW: thr_crit_bup = rb_thread_critical; rb_thread_critical = Qtrue; - + + /* This function works on the Tk eventloop thread only. */ if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { window = NULL; } else { @@ -3696,7 +4234,7 @@ ip_rbTkWaitCommand(clientData, interp, objc, objv) #endif if (window == NULL) { - Tcl_AppendResult(interp, "tkwait: ", + Tcl_AppendResult(interp, ": tkwait: ", "no main-window (not Tk application?)", (char*)NULL); rb_thread_critical = thr_crit_bup; @@ -3902,8 +4440,11 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv) thr_crit_bup = rb_thread_critical; rb_thread_critical = Qtrue; - param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); - Tcl_Preserve(param); + /* param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); */ + param = (struct th_vwait_param *)ckalloc(sizeof(struct th_vwait_param)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)param); +#endif param->thread = current_thread; param->done = 0; @@ -3921,8 +4462,15 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv) rb_thread_critical = thr_crit_bup; if (ret != TCL_OK) { - Tcl_Release(param); - Tcl_Free((char *)param); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif #if TCL_MAJOR_VERSION >= 8 Tcl_DecrRefCount(objv[1]); @@ -3945,8 +4493,15 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv) rb_threadVwaitProc, (ClientData) param); } - Tcl_Release(param); - Tcl_Free((char *)param); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif rb_thread_critical = thr_crit_bup; @@ -4087,8 +4642,11 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv) nameString = objv[2]; #endif - param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); - Tcl_Preserve(param); + /* param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); */ + param = (struct th_vwait_param *)ckalloc(sizeof(struct th_vwait_param)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)param); +#endif param->thread = current_thread; param->done = 0; @@ -4112,8 +4670,15 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv) rb_thread_critical = thr_crit_bup; if (ret != TCL_OK) { +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ Tcl_Release(param); - Tcl_Free((char *)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif #if TCL_MAJOR_VERSION >= 8 Tcl_DecrRefCount(objv[2]); @@ -4150,21 +4715,42 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv) thr_crit_bup = rb_thread_critical; rb_thread_critical = Qtrue; +#if 0 /* variable 'tkwin' must keep the token of MainWindow */ if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { window = NULL; } else { window = Tk_NameToWindow(interp, nameString, tkwin); } +#else + if (!tk_stubs_init_p() || tkwin == (Tk_Window)NULL) { + window = NULL; + } else { + /* Tk_NameToWindow() returns right token on non-eventloop thread */ + Tcl_CmdInfo info; + if (Tcl_GetCommandInfo(interp, ".", &info)) { /* check root */ + window = Tk_NameToWindow(interp, nameString, tkwin); + } else { + window = NULL; + } + } +#endif if (window == NULL) { - Tcl_AppendResult(interp, "thread_tkwait: ", + Tcl_AppendResult(interp, ": thread_tkwait: ", "no main-window (not Tk application?)", (char*)NULL); rb_thread_critical = thr_crit_bup; +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ Tcl_Release(param); - Tcl_Free((char *)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif #if TCL_MAJOR_VERSION >= 8 Tcl_DecrRefCount(objv[2]); @@ -4213,8 +4799,15 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv) Tcl_Release(window); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ Tcl_Release(param); - Tcl_Free((char *)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif #if TCL_MAJOR_VERSION >= 8 Tcl_DecrRefCount(objv[2]); @@ -4239,25 +4832,46 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv) thr_crit_bup = rb_thread_critical; rb_thread_critical = Qtrue; +#if 0 /* variable 'tkwin' must keep the token of MainWindow */ if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { window = NULL; } else { window = Tk_NameToWindow(interp, nameString, tkwin); } +#else + if (!tk_stubs_init_p() || tkwin == (Tk_Window)NULL) { + window = NULL; + } else { + /* Tk_NameToWindow() returns right token on non-eventloop thread */ + Tcl_CmdInfo info; + if (Tcl_GetCommandInfo(interp, ".", &info)) { /* check root */ + window = Tk_NameToWindow(interp, nameString, tkwin); + } else { + window = NULL; + } + } +#endif #if TCL_MAJOR_VERSION >= 8 Tcl_DecrRefCount(objv[2]); #endif if (window == NULL) { - Tcl_AppendResult(interp, "thread_tkwait: ", + Tcl_AppendResult(interp, ": thread_tkwait: ", "no main-window (not Tk application?)", (char*)NULL); rb_thread_critical = thr_crit_bup; +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ Tcl_Release(param); - Tcl_Free((char *)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif Tcl_Release(tkwin); Tcl_Release(interp); @@ -4296,8 +4910,15 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv) break; } /* end of 'switch' statement */ - Tcl_Release(param); - Tcl_Free((char *)param); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif /* * Clear out the interpreter's result, since it may have been set @@ -4541,6 +5162,18 @@ ip_finalize(ip) #if 1 DUMP1("destroy root widget"); if (tk_stubs_init_p() && Tk_MainWindow(ip) != (Tk_Window)NULL) { + /* + * On Ruby VM, this code piece may be not called, because + * Tk_MainWindow() returns NULL on a native thread except + * the thread which initialize Tk environment. + * Of course, that is a problem. But maybe not so serious. + * All widgets are destroyed when the Tcl interp is deleted. + * At then, Ruby may raise exceptions on the delete hook + * callbacks which registered for the deleted widgets, and + * may fail to clear objects which depends on the widgets. + * Although it is the problem, it is possibly avoidable by + * rescuing exceptions and the finalize hook of the interp. + */ DUMP1("call Tk_DestroyWindow"); ruby_debug = Qfalse; ruby_verbose = Qnil; @@ -4602,13 +5235,15 @@ ip_free(ptr) DUMP2("slave IP(%lx) should not be deleted", (unsigned long)ptr->ip); free(ptr); + /* ckfree((char*)ptr); */ rb_thread_critical = thr_crit_bup; return; } if (ptr->ip == (Tcl_Interp*)NULL) { DUMP1("ip_free is called for deleted IP"); - free(ptr); + /* free(ptr); */ + ckfree((char*)ptr); rb_thread_critical = thr_crit_bup; return; } @@ -4619,6 +5254,7 @@ ip_free(ptr) ptr->ip = (Tcl_Interp*)NULL; free(ptr); + /* ckfree((char*)ptr); */ rb_thread_critical = thr_crit_bup; } @@ -4740,7 +5376,11 @@ ip_rbNamespaceObjCmd(clientData, interp, objc, objv) int i; char **argv; - argv = (char **)Tcl_Alloc(sizeof(char *) * (objc + 1)); + /* argv = (char **)Tcl_Alloc(sizeof(char *) * (objc + 1)); */ + argv = (char **)ckalloc(sizeof(char *) * (objc + 1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ +#endif for(i = 0; i < objc; i++) { /* argv[i] = Tcl_GetString(objv[i]); */ @@ -4751,7 +5391,15 @@ ip_rbNamespaceObjCmd(clientData, interp, objc, objv) ret = (*(info.proc))(info.clientData, interp, objc, (CONST84 char **)argv); - Tcl_Free((char*)argv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + /* Tcl_Free((char*)argv); */ + ckfree((char*)argv); +#endif } DUMP2("namespace wrapper exit depth == %d", rbtk_eventloop_depth); @@ -4822,15 +5470,25 @@ ip_init(argc, argv, self) Tk_Window mainWin = (Tk_Window)NULL; /* security check */ +#ifdef RUBY_VM if (rb_safe_level() >= 4) { +#else + if (ruby_safe_level >= 4) { +#endif rb_raise(rb_eSecurityError, "Cannot create a TclTkIp object at level %d", - rb_safe_level()); +#ifdef RUBY_VM + rb_safe_level() +#else + ruby_safe_level +#endif + ); } /* create object */ Data_Get_Struct(self, struct tcltkip, ptr); ptr = ALLOC(struct tcltkip); + /* ptr = (struct tcltkip *)ckalloc(sizeof(struct tcltkip)); */ DATA_PTR(self) = ptr; #ifdef RUBY_VM ptr->tk_thread_id = 0; @@ -4943,7 +5601,8 @@ ip_init(argc, argv, self) #endif #ifdef RUBY_VM - ptr->tk_thread_id = Tcl_GetCurrentThread(); + /* set Tk thread ID */ + ptr->tk_thread_id = Tcl_GetCurrentThread(); #endif /* get main window */ mainWin = Tk_MainWindow(ptr->ip); @@ -5008,7 +5667,7 @@ ip_init(argc, argv, self) if (mainWin != (Tk_Window)NULL) { Tk_Release((ClientData)mainWin); } - + return self; } @@ -5020,6 +5679,7 @@ ip_create_slave_core(interp, argc, argv) { struct tcltkip *master = get_ip(interp); struct tcltkip *slave = ALLOC(struct tcltkip); + /* struct tcltkip *slave = (struct tcltkip *)ckalloc(sizeof(struct tcltkip)); */ VALUE safemode; VALUE name; int safe; @@ -5062,6 +5722,10 @@ ip_create_slave_core(interp, argc, argv) #endif /* create slave-ip */ +#ifdef RUBY_VM + /* slave->tk_thread_id = 0; */ + slave->tk_thread_id = master->tk_thread_id; /* == current thread */ +#endif slave->ref_count = 0; slave->allow_ruby_exit = 0; slave->return_value = 0; @@ -5350,6 +6014,12 @@ ip_allow_ruby_exit_set(self, val) "insecure operation on a safe interpreter"); } + /* + * Because of cross-threading, the following line may fail to find + * the MainWindow, even if the Tcl/Tk interpreter has one or more. + * But it has no problem. Current implementation of both type of + * the "exit" command don't need maiinWin token. + */ mainWin = (tk_stubs_init_p())? Tk_MainWindow(ptr->ip): (Tk_Window)NULL; if (RTEST(val)) { @@ -5446,8 +6116,10 @@ ip_is_deleted_p(self) } static VALUE -ip_has_mainwindow_p(self) +ip_has_mainwindow_p_core(self, argc, argv) VALUE self; + int argc; /* dummy */ + VALUE *argv; /* dummy */ { struct tcltkip *ptr = get_ip(self); @@ -5460,6 +6132,14 @@ ip_has_mainwindow_p(self) } } +static VALUE +ip_has_mainwindow_p(self) + VALUE self; +{ + return tk_funcall(ip_has_mainwindow_p_core, 0, (VALUE*)NULL, self); +} + + /*** ruby string <=> tcl object ***/ #if TCL_MAJOR_VERSION >= 8 static VALUE @@ -5469,12 +6149,16 @@ get_str_from_obj(obj) int len, binary = 0; const char *s; volatile VALUE str; +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 4) + int len2; + const char *s2; +#endif #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0 s = Tcl_GetStringFromObj(obj, &len); #else -#if 0 - /* TCL_VERSION >= 8.1 */ +#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 3 + /* TCL_VERSION 8.1 -- 8.3 */ if (Tcl_GetCharLength(obj) != Tcl_UniCharLen(Tcl_GetUnicode(obj))) { /* possibly binary string */ s = Tcl_GetByteArrayFromObj(obj, &len); @@ -5483,29 +6167,30 @@ get_str_from_obj(obj) /* possibly text string */ s = Tcl_GetStringFromObj(obj, &len); } -#else -#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 4 - if (Tcl_GetCharLength(obj) != Tcl_UniCharLen(Tcl_GetUnicode(obj))) { - /* possibly binary string */ - s = Tcl_GetByteArrayFromObj(obj, &len); - binary = 1; +#else /* TCL_VERSION >= 8.4 */ + if (IS_TCL_BYTEARRAY(obj)) { + s = Tcl_GetByteArrayFromObj(obj, &len); + binary = 1; } else { - /* possibly text string */ - s = Tcl_GetStringFromObj(obj, &len); - } -#else /* TCL_VERSION >= 8.5 */ - /* TODO: Known BUG: - Tcl_GetByteArrayFromObj() returns "alloc: invalid block" */ - if (Tcl_GetCharLength(obj) != Tcl_UniCharLen(Tcl_GetUnicode(obj))) { - /* possibly binary string */ - binary = 1; + s = Tcl_GetStringFromObj(obj, &len); } - s = Tcl_GetStringFromObj(obj, &len); -#endif + #endif #endif str = s ? rb_str_new(s, len) : rb_str_new2(""); - if (binary) rb_ivar_set(str, ID_at_enc, rb_str_new2("binary")); + if (binary) { +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_BINARY); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) + } else { +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_UTF8); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8); +#endif + } return str; } @@ -5529,6 +6214,11 @@ get_obj_from_str(str) /* text string */ return Tcl_NewStringObj(s, RSTRING_LEN(str)); } +#ifdef RUBY_VM + } else if (rb_enc_get_index(str) == ENCODING_INDEX_BINARY) { + /* binary string */ + return Tcl_NewByteArrayObj(s, RSTRING_LEN(str)); +#endif } else if (strlen(s) != RSTRING_LEN(str)) { /* probably binary string */ return Tcl_NewByteArrayObj(s, RSTRING_LEN(str)); @@ -5589,6 +6279,7 @@ call_queue_handler(evPtr, flags) DUMP2("call_queue_handler thread : %lx", rb_thread_current()); DUMP2("added by thread : %lx", q->thread); + if (*(q->done)) { DUMP1("processed by another event-loop"); return 0; @@ -5606,10 +6297,13 @@ call_queue_handler(evPtr, flags) return 1; } + /* incr internal handler mark */ + rbtk_internal_eventloop_handler++; + /* check safe-level */ if (rb_safe_level() != q->safe_level) { - /* q_dat = Data_Wrap_Struct(rb_cData,0,0,q); */ - q_dat = Data_Wrap_Struct(rb_cData,call_queue_mark,0,q); + /* q_dat = Data_Wrap_Struct(rb_cData,0,-1,q); */ + q_dat = Data_Wrap_Struct(rb_cData,call_queue_mark,-1,q); ret = rb_funcall(rb_proc_new(callq_safelevel_handler, q_dat), ID_call, 0); rb_gc_force_recycle(q_dat); @@ -5622,6 +6316,9 @@ call_queue_handler(evPtr, flags) /* set result */ RARRAY_PTR(q->result)[0] = ret; + /* decr internal handler mark */ + rbtk_internal_eventloop_handler--; + /* complete */ *(q->done) = -1; @@ -5629,8 +6326,16 @@ call_queue_handler(evPtr, flags) if (RTEST(rb_funcall(q->thread, ID_alive_p, 0, 0))) { DUMP2("back to caller (caller thread:%lx)", q->thread); DUMP2(" (current thread:%lx)", rb_thread_current()); +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE + have_rb_thread_waited_for_value = 1; + rb_thread_wakeup(q->thread); +#else rb_thread_run(q->thread); +#endif DUMP1("finish back to caller"); +#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE + rb_thread_schedule(); +#endif } else { DUMP2("caller is dead (caller thread:%lx)", q->thread); DUMP2(" (current thread:%lx)", rb_thread_current()); @@ -5648,32 +6353,39 @@ tk_funcall(func, argc, argv, obj) VALUE obj; { struct call_queue *callq; -#ifdef RUBY_VM struct tcltkip *ptr; -#endif int *alloc_done; int thr_crit_bup; + int is_tk_evloop_thread; volatile VALUE current = rb_thread_current(); volatile VALUE ip_obj = obj; volatile VALUE result; volatile VALUE ret; - - if (!NIL_P(ip_obj) && deleted_ip(get_ip(ip_obj))) { - return Qnil; + if (!NIL_P(ip_obj) && rb_obj_is_kind_of(ip_obj, tcltkip_class)) { + ptr = get_ip(ip_obj); + if (deleted_ip(ptr)) return Qnil; + } else { + ptr = (struct tcltkip *)NULL; } #ifdef RUBY_VM - ptr = get_ip(ip_obj); + if (ptr) { + /* on Tcl interpreter */ + is_tk_evloop_thread = (ptr->tk_thread_id == (Tcl_ThreadId) 0 + || ptr->tk_thread_id == Tcl_GetCurrentThread()); + } else { + /* on Tcl/Tk library */ + is_tk_evloop_thread = (tk_eventloop_thread_id == (Tcl_ThreadId) 0 + || tk_eventloop_thread_id == Tcl_GetCurrentThread()); + } +#else + is_tk_evloop_thread = 1; #endif - if ( -#ifdef RUBY_VM - (ptr->tk_thread_id == 0 || ptr->tk_thread_id == Tcl_GetCurrentThread()) - && -#endif - (NIL_P(eventloop_thread) || current == eventloop_thread) - ) { + if (is_tk_evloop_thread + && (NIL_P(eventloop_thread) || current == eventloop_thread) + ) { if (NIL_P(eventloop_thread)) { DUMP2("tk_funcall from thread:%lx but no eventloop", current); } else { @@ -5693,18 +6405,29 @@ tk_funcall(func, argc, argv, obj) /* allocate memory (argv cross over thread : must be in heap) */ if (argv) { - VALUE *temp = ALLOC_N(VALUE, argc); + /* VALUE *temp = ALLOC_N(VALUE, argc); */ + VALUE *temp = (VALUE*)ckalloc(sizeof(VALUE) * argc); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)temp); /* XXXXXXXX */ +#endif MEMCPY(temp, argv, VALUE, argc); argv = temp; } /* allocate memory (keep result) */ - alloc_done = (int*)ALLOC(int); + /* alloc_done = (int*)ALLOC(int); */ + alloc_done = (int*)ckalloc(sizeof(int)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */ +#endif *alloc_done = 0; /* allocate memory (freed by Tcl_ServiceEvent) */ - callq = (struct call_queue *)Tcl_Alloc(sizeof(struct call_queue)); + /* callq = (struct call_queue *)Tcl_Alloc(sizeof(struct call_queue)); */ + callq = (struct call_queue *)ckalloc(sizeof(struct call_queue)); +#if 1 /* use Tcl_Preserve/Release */ Tcl_Preserve(callq); +#endif /* allocate result obj */ result = rb_ary_new3(1, Qnil); @@ -5723,9 +6446,13 @@ tk_funcall(func, argc, argv, obj) /* add the handler to Tcl event queue */ DUMP1("add handler"); #ifdef RUBY_VM - if (ptr->tk_thread_id) { + if (ptr && ptr->tk_thread_id) { Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(callq->ev), TCL_QUEUE_HEAD); Tcl_ThreadAlert(ptr->tk_thread_id); + } else if (tk_eventloop_thread_id) { + Tcl_ThreadQueueEvent(tk_eventloop_thread_id, + &(callq->ev), TCL_QUEUE_HEAD); + Tcl_ThreadAlert(tk_eventloop_thread_id); } else { Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD); } @@ -5739,22 +6466,47 @@ tk_funcall(func, argc, argv, obj) DUMP2("wait for handler (current thread:%lx)", current); while(*alloc_done >= 0) { DUMP2("*** wait for handler (current thread:%lx)", current); - rb_thread_stop(); + rb_thread_stop(); DUMP2("*** wakeup (current thread:%lx)", current); } DUMP2("back from handler (current thread:%lx)", current); /* get result & free allocated memory */ ret = RARRAY_PTR(result)[0]; - free(alloc_done); - if (argv) free(argv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */ +#endif + /* free(alloc_done); */ + ckfree((char*)alloc_done); +#endif + /* if (argv) free(argv); */ + if (argv) { + /* if argv != NULL, alloc as 'temp' */ +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + ckfree((char*)argv); +#endif + } +#if 1 /* use Tcl_Preserve/Release */ Tcl_Release(callq); +#else + ckfree((char*)callq); +#endif /* exception? */ if (rb_obj_is_kind_of(ret, rb_eException)) { DUMP1("raise exception"); - rb_exc_raise(ret); + /* rb_exc_raise(ret); */ + rb_exc_raise(rb_exc_new3(rb_obj_class(ret), + rb_funcall(ret, ID_to_s, 0, 0))); } DUMP1("exit tk_funcall"); @@ -5825,19 +6577,35 @@ ip_eval_real(self, cmd_str, cmd_len) ret = rb_protect(call_tcl_eval, (VALUE)&inf, &status); switch(status) { case TAG_RAISE: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eException, "unknown exception"); } else { +#ifdef RUBY_VM rbtk_pending_exception = rb_errinfo(); +#else + rbtk_pending_exception = ruby_errinfo; +#endif } break; case TAG_FATAL: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL"); } else { +#ifdef RUBY_VM rbtk_pending_exception = rb_errinfo(); +#else + rbtk_pending_exception = ruby_errinfo; +#endif } } #endif @@ -5960,17 +6728,26 @@ eval_queue_handler(evPtr, flags) return 1; } + /* incr internal handler mark */ + rbtk_internal_eventloop_handler++; + /* check safe-level */ if (rb_safe_level() != q->safe_level) { -#if 0 #ifdef HAVE_NATIVETHREAD - if (!ruby_native_thread_p()) { - rb_bug("cross-thread violation on eval_queue_handler()"); - } +#ifdef RUBY_VM +#if 0 + if (!ruby_native_thread_p()) { + rb_bug("cross-thread violation on eval_queue_handler()"); + } +#endif +#else + if (!is_ruby_native_thread()) { + rb_bug("cross-thread violation on eval_queue_handler()"); + } #endif #endif - /* q_dat = Data_Wrap_Struct(rb_cData,0,0,q); */ - q_dat = Data_Wrap_Struct(rb_cData,eval_queue_mark,0,q); + /* q_dat = Data_Wrap_Struct(rb_cData,0,-1,q); */ + q_dat = Data_Wrap_Struct(rb_cData,eval_queue_mark,-1,q); ret = rb_funcall(rb_proc_new(evq_safelevel_handler, q_dat), ID_call, 0); rb_gc_force_recycle(q_dat); @@ -5981,6 +6758,9 @@ eval_queue_handler(evPtr, flags) /* set result */ RARRAY_PTR(q->result)[0] = ret; + /* decr internal handler mark */ + rbtk_internal_eventloop_handler--; + /* complete */ *(q->done) = -1; @@ -5988,8 +6768,16 @@ eval_queue_handler(evPtr, flags) if (RTEST(rb_funcall(q->thread, ID_alive_p, 0, 0))) { DUMP2("back to caller (caller thread:%lx)", q->thread); DUMP2(" (current thread:%lx)", rb_thread_current()); +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE + have_rb_thread_waited_for_value = 1; + rb_thread_wakeup(q->thread); +#else rb_thread_run(q->thread); +#endif DUMP1("finish back to caller"); +#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE + rb_thread_schedule(); +#endif } else { DUMP2("caller is dead (caller thread:%lx)", q->thread); DUMP2(" (current thread:%lx)", rb_thread_current()); @@ -6051,16 +6839,27 @@ ip_eval(self, str) rb_thread_critical = Qtrue; /* allocate memory (protected from Tcl_ServiceEvent) */ - alloc_done = (int*)ALLOC(int); + /* alloc_done = (int*)ALLOC(int); */ + alloc_done = (int*)ckalloc(sizeof(int)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */ +#endif *alloc_done = 0; - eval_str = ALLOC_N(char, RSTRING_LEN(str) + 1); + /* eval_str = ALLOC_N(char, RSTRING_LEN(str) + 1); */ + eval_str = ckalloc(sizeof(char) * (RSTRING_LEN(str) + 1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)eval_str); /* XXXXXXXX */ +#endif memcpy(eval_str, RSTRING_PTR(str), RSTRING_LEN(str)); eval_str[RSTRING_LEN(str)] = 0; /* allocate memory (freed by Tcl_ServiceEvent) */ - evq = (struct eval_queue *)Tcl_Alloc(sizeof(struct eval_queue)); + /* evq = (struct eval_queue *)Tcl_Alloc(sizeof(struct eval_queue)); */ + evq = (struct eval_queue *)ckalloc(sizeof(struct eval_queue)); +#if 1 /* use Tcl_Preserve/Release */ Tcl_Preserve(evq); +#endif /* allocate result obj */ result = rb_ary_new3(1, Qnil); @@ -6096,7 +6895,7 @@ ip_eval(self, str) DUMP2("wait for handler (current thread:%lx)", current); while(*alloc_done >= 0) { DUMP2("*** wait for handler (current thread:%lx)", current); - rb_thread_stop(); + rb_thread_stop(); DUMP2("*** wakeup (current thread:%lx)", current); } DUMP2("back from handler (current thread:%lx)", current); @@ -6104,12 +6903,35 @@ ip_eval(self, str) /* get result & free allocated memory */ ret = RARRAY_PTR(result)[0]; - free(alloc_done); - free(eval_str); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */ +#endif + /* free(alloc_done); */ + ckfree((char*)alloc_done); +#endif +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)eval_str, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)eval_str); /* XXXXXXXX */ +#endif + /* free(eval_str); */ + ckfree(eval_str); +#endif +#if 1 /* use Tcl_Preserve/Release */ Tcl_Release(evq); +#else + ckfree((char*)evq); +#endif if (rb_obj_is_kind_of(ret, rb_eException)) { - rb_exc_raise(ret); + DUMP1("raise exception"); + /* rb_exc_raise(ret); */ + rb_exc_raise(rb_exc_new3(rb_obj_class(ret), + rb_funcall(ret, ID_to_s, 0, 0))); } return ret; @@ -6264,7 +7086,12 @@ lib_toUTF8_core(ip_obj, src, encodename) if (NIL_P(encodename)) { if (TYPE(str) == T_STRING) { volatile VALUE enc; + +#ifdef RUBY_VM + enc = rb_funcall(rb_obj_encoding(str), ID_to_s, 0, 0); +#else enc = rb_attr_get(str, ID_at_enc); +#endif if (NIL_P(enc)) { if (NIL_P(ip_obj)) { encoding = (Tcl_Encoding)NULL; @@ -6283,6 +7110,10 @@ lib_toUTF8_core(ip_obj, src, encodename) } else { StringValue(enc); if (strcmp(RSTRING_PTR(enc), "binary") == 0) { +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_BINARY); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); rb_thread_critical = thr_crit_bup; return str; } @@ -6296,6 +7127,14 @@ lib_toUTF8_core(ip_obj, src, encodename) } } else { StringValue(encodename); + if (strcmp(RSTRING_PTR(encodename), "binary") == 0) { +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_BINARY); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); + rb_thread_critical = thr_crit_bup; + return str; + } encoding = Tcl_GetEncoding(interp, RSTRING_PTR(encodename)); if (encoding == (Tcl_Encoding)NULL) { /* @@ -6312,7 +7151,8 @@ lib_toUTF8_core(ip_obj, src, encodename) rb_thread_critical = thr_crit_bup; return str; } - buf = ALLOC_N(char,RSTRING_LEN(str)+1); + buf = ALLOC_N(char, RSTRING_LEN(str)+1); + /* buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); */ memcpy(buf, RSTRING_PTR(str), RSTRING_LEN(str)); buf[RSTRING_LEN(str)] = 0; @@ -6324,7 +7164,10 @@ lib_toUTF8_core(ip_obj, src, encodename) /* str = rb_tainted_str_new2(Tcl_DStringValue(&dstr)); */ /* str = rb_str_new2(Tcl_DStringValue(&dstr)); */ str = rb_str_new(Tcl_DStringValue(&dstr), Tcl_DStringLength(&dstr)); - rb_ivar_set(str, ID_at_enc, rb_tainted_str_new2("utf-8")); +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_UTF8); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8); if (taint_flag) OBJ_TAINT(str); if (encoding != (Tcl_Encoding)NULL) { @@ -6333,6 +7176,7 @@ lib_toUTF8_core(ip_obj, src, encodename) Tcl_DStringFree(&dstr); free(buf); + /* ckfree(buf); */ rb_thread_critical = thr_crit_bup; #endif @@ -6411,9 +7255,20 @@ lib_fromUTF8_core(ip_obj, src, encodename) if (!NIL_P(enc)) { StringValue(enc); if (strcmp(RSTRING_PTR(enc), "binary") == 0) { +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_BINARY); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); rb_thread_critical = thr_crit_bup; return str; } +#ifdef RUBY_VM + } else if (rb_enc_get_index(str) == ENCODING_INDEX_BINARY) { + rb_enc_associate_index(str, ENCODING_INDEX_BINARY); + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); + rb_thread_critical = thr_crit_bup; + return str; +#endif } } @@ -6446,7 +7301,10 @@ lib_fromUTF8_core(ip_obj, src, encodename) RSTRING_LEN(str)), &len); str = rb_tainted_str_new(s, len); - rb_ivar_set(str, ID_at_enc, rb_tainted_str_new2("binary")); +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_BINARY); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); rb_thread_critical = thr_crit_bup; return str; @@ -6471,7 +7329,8 @@ lib_fromUTF8_core(ip_obj, src, encodename) return rb_tainted_str_new2(""); } - buf = ALLOC_N(char,strlen(RSTRING_PTR(str))+1); + buf = ALLOC_N(char, RSTRING_LEN(str)+1); + /* buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); */ memcpy(buf, RSTRING_PTR(str), RSTRING_LEN(str)); buf[RSTRING_LEN(str)] = 0; @@ -6483,6 +7342,19 @@ lib_fromUTF8_core(ip_obj, src, encodename) /* str = rb_tainted_str_new2(Tcl_DStringValue(&dstr)); */ /* str = rb_str_new2(Tcl_DStringValue(&dstr)); */ str = rb_str_new(Tcl_DStringValue(&dstr), Tcl_DStringLength(&dstr)); +#ifdef RUBY_VM + if (interp) { + /* can access encoding_table of TclTkIp */ + /* -> try to use encoding_table */ + VALUE tbl = ip_get_encoding_table(ip_obj); + VALUE encobj = encoding_table_get_obj(tbl, encodename); + rb_enc_associate_index(str, rb_to_encoding_index(encobj)); + } else { + /* cannot access encoding_table of TclTkIp */ + /* -> try to find on Ruby Encoding */ + rb_enc_associate_index(str, rb_enc_find_index(RSTRING_PTR(encodename))); + } +#endif rb_ivar_set(str, ID_at_enc, encodename); if (taint_flag) OBJ_TAINT(str); @@ -6493,6 +7365,7 @@ lib_fromUTF8_core(ip_obj, src, encodename) Tcl_DStringFree(&dstr); free(buf); + /* ckfree(buf); */ rb_thread_critical = thr_crit_bup; #endif @@ -6550,11 +7423,19 @@ lib_UTF_backslash_core(self, str, all_bs) thr_crit_bup = rb_thread_critical; rb_thread_critical = Qtrue; - src_buf = ALLOC_N(char,RSTRING_LEN(str)+1); + /* src_buf = ALLOC_N(char, RSTRING_LEN(str)+1); */ + src_buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)src_buf); /* XXXXXXXX */ +#endif memcpy(src_buf, RSTRING_PTR(str), RSTRING_LEN(str)); src_buf[RSTRING_LEN(str)] = 0; - dst_buf = ALLOC_N(char,RSTRING_LEN(str)+1); + /* dst_buf = ALLOC_N(char, RSTRING_LEN(str)+1); */ + dst_buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)dst_buf); /* XXXXXXXX */ +#endif ptr = src_buf; while(RSTRING_LEN(str) > ptr - src_buf) { @@ -6568,9 +7449,29 @@ lib_UTF_backslash_core(self, str, all_bs) str = rb_str_new(dst_buf, dst_len); if (taint_flag) OBJ_TAINT(str); +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_UTF8); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8); - free(src_buf); - free(dst_buf); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)src_buf, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)src_buf); /* XXXXXXXX */ +#endif + /* free(src_buf); */ + ckfree(src_buf); +#endif +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)dst_buf, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)dst_buf); /* XXXXXXXX */ +#endif + /* free(dst_buf); */ + ckfree(dst_buf); +#endif rb_thread_critical = thr_crit_bup; #endif @@ -6661,8 +7562,11 @@ invoke_tcl_proc(arg) #if TCL_MAJOR_VERSION >= 8 if (!inf->cmdinfo.isNativeObjectProc) { /* string interface */ - // argv = (char **)ALLOC_N(char *, argc+1); /* XXXXXXXXXX */ + /* argv = (char **)ALLOC_N(char *, argc+1);*/ /* XXXXXXXXXX */ argv = (char **)ckalloc(sizeof(char *)*(argc+1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ +#endif for (i = 0; i < argc; ++i) { argv[i] = Tcl_GetStringFromObj(inf->objv[i], &len); } @@ -6675,7 +7579,6 @@ invoke_tcl_proc(arg) /* Invoke the C procedure */ #if TCL_MAJOR_VERSION >= 8 if (inf->cmdinfo.isNativeObjectProc) { - int ret_val; inf->ptr->return_value = (*(inf->cmdinfo.objProc))(inf->cmdinfo.objClientData, inf->ptr->ip, inf->objc, inf->objv); @@ -6688,8 +7591,15 @@ invoke_tcl_proc(arg) = (*(inf->cmdinfo.proc))(inf->cmdinfo.clientData, inf->ptr->ip, argc, (CONST84 char **)argv); - //free(argv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + /* free(argv); */ ckfree((char*)argv); +#endif #else /* TCL_MAJOR_VERSION < 8 */ inf->ptr->return_value @@ -6745,6 +7655,9 @@ ip_invoke_core(interp, argc, argv) cmd = argv[0]; #endif + /* get the data struct */ + ptr = get_ip(interp); + /* ip is deleted? */ if (deleted_ip(ptr)) { return rb_tainted_str_new2(""); @@ -6794,15 +7707,22 @@ ip_invoke_core(interp, argc, argv) unknown_flag = 1; #if TCL_MAJOR_VERSION >= 8 - //unknown_objv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, objc+2); + /* unknown_objv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, objc+2); */ unknown_objv = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj *) * (objc+2)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)unknown_objv); /* XXXXXXXX */ +#endif unknown_objv[0] = Tcl_NewStringObj("::unknown", 9); Tcl_IncrRefCount(unknown_objv[0]); memcpy(unknown_objv + 1, objv, sizeof(Tcl_Obj *)*objc); unknown_objv[++objc] = (Tcl_Obj*)NULL; objv = unknown_objv; #else - unknown_argv = (char **)ALLOC_N(char *, argc+2); + /* unknown_argv = (char **)ALLOC_N(char *, argc+2); */ + unknown_argv = (char **)ckalloc(sizeof(char *) * (argc+2)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)unknown_argv); /* XXXXXXXX */ +#endif unknown_argv[0] = strdup("unknown"); memcpy(unknown_argv + 1, argv, sizeof(char *)*argc); unknown_argv[++argc] = (char *)NULL; @@ -6831,19 +7751,35 @@ ip_invoke_core(interp, argc, argv) ret = rb_protect(invoke_tcl_proc, (VALUE)&inf, &status); switch(status) { case TAG_RAISE: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eException, "unknown exception"); } else { +#ifdef RUBY_VM rbtk_pending_exception = rb_errinfo(); +#else + rbtk_pending_exception = ruby_errinfo; +#endif } break; case TAG_FATAL: +#ifdef RUBY_VM if (NIL_P(rb_errinfo())) { +#else + if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL"); } else { +#ifdef RUBY_VM rbtk_pending_exception = rb_errinfo(); +#else + rbtk_pending_exception = ruby_errinfo; +#endif } } @@ -6855,8 +7791,11 @@ ip_invoke_core(interp, argc, argv) int i; /* string interface */ - //argv = (char **)ALLOC_N(char *, argc+1); + /* argv = (char **)ALLOC_N(char *, argc+1); */ argv = (char **)ckalloc(sizeof(char *) * (argc+1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ +#endif for (i = 0; i < argc; ++i) { argv[i] = Tcl_GetStringFromObj(objv[i], &len); } @@ -6885,8 +7824,15 @@ ip_invoke_core(interp, argc, argv) ptr->return_value = (*info.proc)(info.clientData, ptr->ip, argc, (CONST84 char **)argv); - //free(argv); - ckfree(argv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + /* free(argv); */ + ckfree((char*)argv); +#endif #else /* TCL_MAJOR_VERSION < 8 */ ptr->return_value = (*info.proc)(info.clientData, ptr->ip, @@ -6899,10 +7845,27 @@ ip_invoke_core(interp, argc, argv) if (unknown_flag) { #if TCL_MAJOR_VERSION >= 8 Tcl_DecrRefCount(objv[0]); - free(objv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)objv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)objv); /* XXXXXXXX */ +#endif + /* free(objv); */ + ckfree((char*)objv); +#endif #else free(argv[0]); - free(argv); + /* ckfree(argv[0]); */ +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + /* free(argv); */ + ckfree((char*)argv); +#endif #endif } @@ -6957,8 +7920,11 @@ alloc_invoke_arguments(argc, argv) /* memory allocation */ #if TCL_MAJOR_VERSION >= 8 - //av = ALLOC_N(Tcl_Obj *, argc+1); /* XXXXXXXXXX */ + /* av = ALLOC_N(Tcl_Obj *, argc+1);*/ /* XXXXXXXXXX */ av = (Tcl_Obj**)ckalloc(sizeof(Tcl_Obj *)*(argc+1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)av); /* XXXXXXXX */ +#endif for (i = 0; i < argc; ++i) { av[i] = get_obj_from_str(argv[i]); Tcl_IncrRefCount(av[i]); @@ -6967,7 +7933,11 @@ alloc_invoke_arguments(argc, argv) #else /* TCL_MAJOR_VERSION < 8 */ /* string interface */ - av = ALLOC_N(char *, argc+1); + /* av = ALLOC_N(char *, argc+1); */ + av = (char**)ckalloc(sizeof(char *) * (argc+1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)av); /* XXXXXXXX */ +#endif for (i = 0; i < argc; ++i) { av[i] = strdup(StringValuePtr(argv[i])); } @@ -6998,9 +7968,24 @@ free_invoke_arguments(argc, av) #endif } #if TCL_MAJOR_VERSION >= 8 +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)av, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)av); /* XXXXXXXX */ +#endif ckfree((char*)av); +#endif #else /* TCL_MAJOR_VERSION < 8 */ - free(av); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)av, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)av); /* XXXXXXXX */ +#endif + /* free(av); */ + ckfree((char*)av); +#endif #endif } @@ -7064,6 +8049,7 @@ invoke_queue_handler(evPtr, flags) struct invoke_queue *q = (struct invoke_queue *)evPtr; volatile VALUE ret; volatile VALUE q_dat; + struct tcltkip *ptr; DUMP2("do_invoke_queue_handler : evPtr = %p", evPtr); DUMP2("invoke queue_thread : %lx", rb_thread_current()); @@ -7079,10 +8065,20 @@ invoke_queue_handler(evPtr, flags) /* process it */ *(q->done) = 1; + /* deleted ipterp ? */ + ptr = get_ip(q->interp); + if (deleted_ip(ptr)) { + /* deleted IP --> ignore */ + return 1; + } + + /* incr internal handler mark */ + rbtk_internal_eventloop_handler++; + /* check safe-level */ if (rb_safe_level() != q->safe_level) { /* q_dat = Data_Wrap_Struct(rb_cData,0,0,q); */ - q_dat = Data_Wrap_Struct(rb_cData,invoke_queue_mark,0,q); + q_dat = Data_Wrap_Struct(rb_cData,invoke_queue_mark,-1,q); ret = rb_funcall(rb_proc_new(ivq_safelevel_handler, q_dat), ID_call, 0); rb_gc_force_recycle(q_dat); @@ -7095,6 +8091,9 @@ invoke_queue_handler(evPtr, flags) /* set result */ RARRAY_PTR(q->result)[0] = ret; + /* decr internal handler mark */ + rbtk_internal_eventloop_handler--; + /* complete */ *(q->done) = -1; @@ -7102,8 +8101,16 @@ invoke_queue_handler(evPtr, flags) if (RTEST(rb_funcall(q->thread, ID_alive_p, 0, 0))) { DUMP2("back to caller (caller thread:%lx)", q->thread); DUMP2(" (current thread:%lx)", rb_thread_current()); +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE + have_rb_thread_waited_for_value = 1; + rb_thread_wakeup(q->thread); +#else rb_thread_run(q->thread); +#endif DUMP1("finish back to caller"); +#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE + rb_thread_schedule(); +#endif } else { DUMP2("caller is dead (caller thread:%lx)", q->thread); DUMP2(" (current thread:%lx)", rb_thread_current()); @@ -7143,8 +8150,8 @@ ip_invoke_with_position(argc, argv, obj, position) #ifdef RUBY_VM ptr = get_ip(ip_obj); -#endif DUMP2("status: ptr->tk_thread_id %d", ptr->tk_thread_id); +#endif DUMP2("status: Tcl_GetCurrentThread %d", Tcl_GetCurrentThread()); DUMP2("status: eventloopt_thread %lx", eventloop_thread); @@ -7167,6 +8174,8 @@ ip_invoke_with_position(argc, argv, obj, position) return result; } + DUMP2("invoke from thread %lx (NOT current eventloop)", current); + thr_crit_bup = rb_thread_critical; rb_thread_critical = Qtrue; @@ -7174,13 +8183,19 @@ ip_invoke_with_position(argc, argv, obj, position) av = alloc_invoke_arguments(argc, argv); /* allocate memory (keep result) */ - //alloc_done = (int*)ALLOC(int); + /* alloc_done = (int*)ALLOC(int); */ alloc_done = (int*)ckalloc(sizeof(int)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */ +#endif *alloc_done = 0; /* allocate memory (freed by Tcl_ServiceEvent) */ + /* ivq = (struct invoke_queue *)Tcl_Alloc(sizeof(struct invoke_queue)); */ ivq = (struct invoke_queue *)ckalloc(sizeof(struct invoke_queue)); - Tcl_Preserve(ivq); +#if 1 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)ivq); /* XXXXXXXX */ +#endif /* allocate result obj */ result = rb_ary_new3(1, Qnil); @@ -7213,16 +8228,31 @@ ip_invoke_with_position(argc, argv, obj, position) /* wait for the handler to be processed */ DUMP2("wait for handler (current thread:%lx)", current); while(*alloc_done >= 0) { - rb_thread_stop(); + rb_thread_stop(); } DUMP2("back from handler (current thread:%lx)", current); /* get result & free allocated memory */ - ret = RARRAY_PTR(result)[0]; - //free(alloc_done); + ret = RARRAY(result)->ptr[0]; +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */ +#endif + /* free(alloc_done); */ ckfree((char*)alloc_done); +#endif +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)ivq, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 1 /* use Tcl_Preserve/Release */ Tcl_Release(ivq); +#else + ckfree((char*)ivq); +#endif +#endif /* free allocated memory */ free_invoke_arguments(argc, av); @@ -7230,9 +8260,12 @@ ip_invoke_with_position(argc, argv, obj, position) /* exception? */ if (rb_obj_is_kind_of(ret, rb_eException)) { DUMP1("raise exception"); - rb_exc_raise(ret); + /* rb_exc_raise(ret); */ + rb_exc_raise(rb_exc_new3(rb_obj_class(ret), + rb_funcall(ret, ID_to_s, 0, 0))); } + DUMP1("exit ip_invoke"); return ret; } @@ -7692,6 +8725,10 @@ lib_split_tklist_core(ip_obj, list_str) volatile VALUE ary, elem; int idx; int taint_flag = OBJ_TAINTED(list_str); +#ifdef RUBY_VM + int list_enc_idx; + volatile VALUE list_ivar_enc; +#endif int result; VALUE old_gc; @@ -7706,6 +8743,10 @@ lib_split_tklist_core(ip_obj, list_str) } StringValue(list_str); +#ifdef RUBY_VM + list_enc_idx = rb_enc_get_index(list_str); + list_ivar_enc = rb_ivar_get(list_str, ID_at_enc); +#endif { #if TCL_MAJOR_VERSION >= 8 @@ -7744,10 +8785,22 @@ lib_split_tklist_core(ip_obj, list_str) for(idx = 0; idx < objc; idx++) { elem = get_str_from_obj(objv[idx]); +#ifdef RUBY_VM + if (rb_enc_get_index(elem) == ENCODING_INDEX_BINARY) { + rb_enc_associate_index(elem, ENCODING_INDEX_BINARY); + rb_ivar_set(elem, ID_at_enc, ENCODING_NAME_BINARY); + } else { + rb_enc_associate_index(elem, list_enc_idx); + rb_ivar_set(elem, ID_at_enc, list_ivar_enc); + } +#endif if (taint_flag) OBJ_TAINT(elem); + /* RARRAY(ary)->ptr[idx] = elem; */ rb_ary_push(ary, elem); } + /* RARRAY(ary)->len = objc; */ + if (old_gc == Qfalse) rb_gc_enable(); rb_thread_critical = thr_crit_bup; @@ -7784,8 +8837,11 @@ lib_split_tklist_core(ip_obj, list_str) elem = rb_str_new2(argv[idx]); } /* rb_ivar_set(elem, ID_at_enc, rb_str_new2("binary")); */ - rb_ary_push(ary, elem); + /* RARRAY(ary)->ptr[idx] = elem; */ + rb_ary_push(ary, elem) } + /* RARRAY(ary)->len = argc; */ + if (old_gc == Qfalse) rb_gc_enable(); #endif } @@ -7833,7 +8889,11 @@ lib_merge_tklist(argc, argv, obj) old_gc = rb_gc_disable(); /* based on Tcl/Tk's Tcl_Merge() */ - flagPtr = ALLOC_N(int, argc); + /* flagPtr = ALLOC_N(int, argc); */ + flagPtr = (int *)ckalloc(sizeof(int) * argc); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)flagPtr); /* XXXXXXXXXX */ +#endif /* pass 1 */ len = 1; @@ -7841,7 +8901,7 @@ lib_merge_tklist(argc, argv, obj) if (OBJ_TAINTED(argv[num])) taint_flag = 1; dst = StringValuePtr(argv[num]); #if TCL_MAJOR_VERSION >= 8 - len += Tcl_ScanCountedElement(dst, RSTRING_LEN(argv[num]), + len += Tcl_ScanCountedElement(dst, RSTRING_LEN(argv[num]), &flagPtr[num]) + 1; #else /* TCL_MAJOR_VERSION < 8 */ len += Tcl_ScanElement(dst, &flagPtr[num]) + 1; @@ -7849,7 +8909,11 @@ lib_merge_tklist(argc, argv, obj) } /* pass 2 */ + /* result = (char *)Tcl_Alloc(len); */ result = (char *)ckalloc(len); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)result); +#endif dst = result; for(num = 0; num < argc; num++) { #if TCL_MAJOR_VERSION >= 8 @@ -7869,12 +8933,28 @@ lib_merge_tklist(argc, argv, obj) dst[-1] = 0; } - free(flagPtr); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)flagPtr, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)flagPtr); +#endif + /* free(flagPtr); */ + ckfree((char*)flagPtr); +#endif /* create object */ str = rb_str_new(result, dst - result - 1); if (taint_flag) OBJ_TAINT(str); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)result, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)result); /* XXXXXXXXXXX */ +#endif + /* Tcl_Free(result); */ ckfree(result); +#endif if (old_gc == Qfalse) rb_gc_enable(); rb_thread_critical = thr_crit_bup; @@ -7919,17 +8999,15 @@ lib_conv_listelement(self, src) return dst; } - static VALUE lib_getversion(self) VALUE self; { - int major, minor, patchlevel, type; volatile VALUE type_name; - Tcl_GetVersion(&major, &minor, &patchlevel, &type); + set_tcltk_version(); - switch(type) { + switch(tcltk_version.type) { case TCL_ALPHA_RELEASE: type_name = rb_str_new2("alpha"); break; @@ -7943,9 +9021,10 @@ lib_getversion(self) type_name = rb_str_new2("unknown"); } - return rb_ary_new3(5, INT2NUM(major), INT2NUM(minor), - INT2NUM(type), type_name, - INT2NUM(patchlevel)); + return rb_ary_new3(5, INT2NUM(tcltk_version.major), + INT2NUM(tcltk_version.minor), + INT2NUM(tcltk_version.type), type_name, + INT2NUM(tcltk_version.patchlevel)); } @@ -7970,6 +9049,7 @@ tcltklib_compile_info() + strlen("unknown tcl_threads"); info = ALLOC_N(char, size); + /* info = ckalloc(sizeof(char) * size); */ /* SEGV */ sprintf(info, form, TCLTKLIB_RELEASE_DATE, @@ -8005,10 +9085,527 @@ tcltklib_compile_info() ret = rb_obj_freeze(rb_str_new2(info)); free(info); + /* ckfree(info); */ return ret; } + +/*###############################################*/ + +static VALUE +create_dummy_encoding_for_tk_core(interp, name, error_mode) + VALUE interp; + VALUE name; + VALUE error_mode; +{ + struct tcltkip *ptr = get_ip(interp); + + rb_secure(4); + + StringValue(name); + +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) + if (Tcl_GetEncoding(ptr->ip, RSTRING_PTR(name)) == (Tcl_Encoding) NULL) { + if (RTEST(error_mode)) { + rb_raise(rb_eArgError, "invalid Tk encoding name '%s'", + RSTRING_PTR(name)); + } else { + return Qnil; + } + } +#endif + +#ifdef RUBY_VM + if (RTEST(rb_define_dummy_encoding(RSTRING_PTR(name)))) { + int idx = rb_enc_find_index(StringValueCStr(name)); + return rb_enc_from_encoding(rb_enc_from_index(idx)); + } else { + if (RTEST(error_mode)) { + rb_raise(rb_eRuntimeError, "fail to create dummy encoding for '%s'", + RSTRING_PTR(name)); + } else { + return Qnil; + } + } +#else + return name; +#endif +} +static VALUE +create_dummy_encoding_for_tk(interp, name) + VALUE interp; + VALUE name; +{ + return create_dummy_encoding_for_tk_core(interp, name, Qtrue); +} + + +#ifdef RUBY_VM +static int +update_encoding_table(table, interp, error_mode) + VALUE table; + VALUE interp; + VALUE error_mode; +{ + struct tcltkip *ptr; + int retry = 0; + int i, idx, objc; + Tcl_Obj **objv; + Tcl_Obj *enc_list; + volatile VALUE encname = Qnil; + volatile VALUE encobj = Qnil; + + /* interpreter check */ + if (NIL_P(interp)) return 0; + ptr = get_ip(interp); + if (ptr == (struct tcltkip *) NULL) return 0; + if (deleted_ip(ptr)) return 0; + + /* get Tcl's encoding list */ + Tcl_GetEncodingNames(ptr->ip); + enc_list = Tcl_GetObjResult(ptr->ip); + Tcl_IncrRefCount(enc_list); + + if (Tcl_ListObjGetElements(ptr->ip, enc_list, + &objc, &objv) != TCL_OK) { + Tcl_DecrRefCount(enc_list); + /* rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names");*/ + return 0; + } + + /* check each encoding name */ + for(i = 0; i < objc; i++) { + encname = rb_str_new2(Tcl_GetString(objv[i])); + if (NIL_P(rb_hash_lookup(table, encname))) { + /* new Tk encoding -> add to table */ + idx = rb_enc_find_index(StringValueCStr(encname)); + if (idx < 0) { + encobj = create_dummy_encoding_for_tk_core(interp,encname,error_mode); + } else { + encobj = rb_enc_from_encoding(rb_enc_from_index(idx)); + } + encname = rb_obj_freeze(encname); + rb_hash_aset(table, encname, encobj); + if (!NIL_P(encobj) && NIL_P(rb_hash_lookup(table, encobj))) { + rb_hash_aset(table, encobj, encname); + } + retry = 1; + } + } + + Tcl_DecrRefCount(enc_list); + + return retry; +} + +static VALUE +encoding_table_get_name_core(table, enc_arg, error_mode) + VALUE table; + VALUE enc_arg; + VALUE error_mode; +{ + volatile VALUE enc = enc_arg; + volatile VALUE name = Qnil; + volatile VALUE tmp = Qnil; + volatile VALUE interp = rb_ivar_get(table, ID_at_interp); + struct tcltkip *ptr = (struct tcltkip *) NULL; + int idx; + + /* deleted interp ? */ + if (!NIL_P(interp)) { + ptr = get_ip(interp); + if (deleted_ip(ptr)) { + ptr = (struct tcltkip *) NULL; + } + } + + /* encoding argument check */ + /* 1st: default encoding setting of interp */ + if (ptr && NIL_P(enc)) { + if (rb_respond_to(interp, ID_encoding_name)) { + enc = rb_funcall(interp, ID_encoding_name, 0, 0); + } + } + /* 2nd: encoding system of Tcl/Tk */ + if (NIL_P(enc)) { + enc = rb_str_new2(Tcl_GetEncodingName((Tcl_Encoding)NULL)); + } + /* 3rd: Encoding.default_external */ + if (NIL_P(enc)) { + enc = rb_enc_default_external(); + } + + if (RTEST(rb_obj_is_kind_of(enc, cRubyEncoding))) { + /* Ruby's Encoding object */ + name = rb_hash_lookup(table, enc); + if (!NIL_P(name)) { + /* find */ + return name; + } + + /* is it new ? */ + /* update check of Tk encoding names */ + if (update_encoding_table(table, interp, error_mode)) { + /* add new relations to the table */ + /* RETRY: registered Ruby encoding? */ + name = rb_hash_lookup(table, enc); + if (!NIL_P(name)) { + /* find */ + return name; + } + } + /* fail to find */ + + } else { + /* String or Symbol? */ + name = rb_funcall(enc, ID_to_s, 0, 0); + + if (!NIL_P(rb_hash_lookup(table, name))) { + /* find */ + return name; + } + + /* is it new ? */ + idx = rb_enc_find_index(StringValueCStr(name)); + if (idx >= 0) { + enc = rb_enc_from_encoding(rb_enc_from_index(idx)); + + /* registered Ruby encoding? */ + tmp = rb_hash_lookup(table, enc); + if (!NIL_P(tmp)) { + /* find */ + return tmp; + } + + /* update check of Tk encoding names */ + if (update_encoding_table(table, interp, error_mode)) { + /* add new relations to the table */ + /* RETRY: registered Ruby encoding? */ + tmp = rb_hash_lookup(table, enc); + if (!NIL_P(tmp)) { + /* find */ + return tmp; + } + } + } + /* fail to find */ + } + + if (RTEST(error_mode)) { + enc = rb_funcall(enc_arg, ID_to_s, 0, 0); + rb_raise(rb_eArgError, "unsupported Tk encoding '%s'", RSTRING_PTR(enc)); + } + return Qnil; +} +static VALUE +encoding_table_get_obj_core(table, enc, error_mode) + VALUE table; + VALUE enc; + VALUE error_mode; +{ + volatile VALUE obj = Qnil; + + obj = rb_hash_lookup(table, + encoding_table_get_name_core(table, enc, error_mode)); + if (RTEST(rb_obj_is_kind_of(obj, cRubyEncoding))) { + return obj; + } else { + return Qnil; + } +} + +#else /* ! RUBY_VM */ +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) +static int +update_encoding_table(table, interp, error_mode) + VALUE table; + VALUE interp; + VALUE error_mode; +{ + struct tcltkip *ptr; + int retry = 0; + int i, idx, objc; + Tcl_Obj **objv; + Tcl_Obj *enc_list; + volatile VALUE encname = Qnil; + volatile VALUE encobj = Qnil; + + /* interpreter check */ + if (NIL_P(interp)) return 0; + ptr = get_ip(interp); + if (ptr == (struct tcltkip *) NULL) return 0; + if (deleted_ip(ptr)) return 0; + + /* get Tcl's encoding list */ + Tcl_GetEncodingNames(ptr->ip); + enc_list = Tcl_GetObjResult(ptr->ip); + Tcl_IncrRefCount(enc_list); + + if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) { + Tcl_DecrRefCount(enc_list); + /* rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names"); */ + return 0; + } + + /* get encoding name and set it to table */ + for(i = 0; i < objc; i++) { + encname = rb_str_new2(Tcl_GetString(objv[i])); + if (NIL_P(rb_hash_lookup(table, encname))) { + /* new Tk encoding -> add to table */ + encname = rb_obj_freeze(encname); + rb_hash_aset(table, encname, encname); + retry = 1; + } + } + + Tcl_DecrRefCount(enc_list); + + return retry; +} + +static VALUE +encoding_table_get_name_core(table, enc, error_mode) + VALUE table; + VALUE enc; + VALUE error_mode; +{ + volatile VALUE name = Qnil; + int retry = 0; + + enc = rb_funcall(enc, ID_to_s, 0, 0); + name = rb_hash_lookup(table, enc); + + if (!NIL_P(name)) { + /* find */ + return name; + } + + /* update check */ + if (update_encoding_table(table, rb_ivar_get(table, ID_at_interp), + error_mode)) { + /* add new relations to the table */ + /* RETRY: registered Ruby encoding? */ + name = rb_hash_lookup(table, enc); + if (!NIL_P(name)) { + /* find */ + return name; + } + } + + if (RTEST(error_mode)) { + rb_raise(rb_eArgError, "unsupported Tk encoding '%s'", RSTRING_PTR(enc)); + } + return Qnil; +} +static VALUE +encoding_table_get_obj_core(table, enc, error_mode) + VALUE table; + VALUE enc; + VALUE error_mode; +{ + return encoding_table_get_name_core(table, enc, error_mode); +} + +#else /* Tcl/Tk 7.x or 8.0 */ +static VALUE +encoding_table_get_name_core(table, enc, error_mode) + VALUE table; + VALUE enc; + VALUE error_mode; +{ + return Qnil; +} +static VALUE +encoding_table_get_obj_core(table, enc, error_mode) + VALUE table; + VALUE enc; + VALUE error_mode; +{ + return Qnil; +} +#endif /* end of dependency for the version of Tcl/Tk */ +#endif + +static VALUE +encoding_table_get_name(table, enc) + VALUE table; + VALUE enc; +{ + return encoding_table_get_name_core(table, enc, Qtrue); +} +static VALUE +encoding_table_get_obj(table, enc) + VALUE table; + VALUE enc; +{ + return encoding_table_get_obj_core(table, enc, Qtrue); +} + +#ifdef RUBY_VM +static VALUE +create_encoding_table(interp) + VALUE interp; +{ + struct tcltkip *ptr = get_ip(interp); + volatile VALUE table = rb_hash_new(); + volatile VALUE encname = Qnil; + volatile VALUE encobj = Qnil; + int i, idx, objc; + Tcl_Obj **objv; + Tcl_Obj *enc_list; + + rb_secure(4); + + /* set 'binary' encoding */ + encobj = rb_enc_from_encoding(rb_enc_from_index(ENCODING_INDEX_BINARY)); + rb_hash_aset(table, ENCODING_NAME_BINARY, encobj); + rb_hash_aset(table, encobj, ENCODING_NAME_BINARY); + + + /* Tcl stub check */ + tcl_stubs_check(); + + /* get Tcl's encoding list */ + Tcl_GetEncodingNames(ptr->ip); + enc_list = Tcl_GetObjResult(ptr->ip); + Tcl_IncrRefCount(enc_list); + + if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) { + Tcl_DecrRefCount(enc_list); + rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names"); + } + + /* get encoding name and set it to table */ + for(i = 0; i < objc; i++) { + int name2obj, obj2name; + + name2obj = 1; obj2name = 1; + encname = rb_obj_freeze(rb_str_new2(Tcl_GetString(objv[i]))); + idx = rb_enc_find_index(StringValueCStr(encname)); + if (idx < 0) { + /* fail to find ruby encoding -> check known encoding */ + if (strcmp(RSTRING_PTR(encname), "identity") == 0) { + name2obj = 1; obj2name = 0; + idx = ENCODING_INDEX_BINARY; + + } else if (strcmp(RSTRING_PTR(encname), "shiftjis") == 0) { + name2obj = 1; obj2name = 0; + idx = rb_enc_find_index("Shift_JIS"); + + } else if (strcmp(RSTRING_PTR(encname), "unicode") == 0) { + name2obj = 1; obj2name = 0; + idx = ENCODING_INDEX_UTF8; + + } else if (strcmp(RSTRING_PTR(encname), "symbol") == 0) { + name2obj = 1; obj2name = 0; + idx = rb_enc_find_index("ASCII-8BIT"); + + } else { + /* regist dummy encoding */ + name2obj = 1; obj2name = 1; + } + } + + if (idx < 0) { + /* unknown encoding -> create dummy */ + encobj = create_dummy_encoding_for_tk(interp, encname); + } else { + encobj = rb_enc_from_encoding(rb_enc_from_index(idx)); + } + + if (name2obj) { + DUMP2("create_encoding_table: name2obj: %s", RSTRING_PTR(encname)); + rb_hash_aset(table, encname, encobj); + } + if (obj2name) { + DUMP2("create_encoding_table: obj2name: %s", RSTRING_PTR(encname)); + rb_hash_aset(table, encobj, encname); + } + } + + Tcl_DecrRefCount(enc_list); + + rb_ivar_set(table, ID_at_interp, interp); + rb_ivar_set(interp, ID_encoding_table, table); + + return table; +} + +#else /* ! RUBY_VM */ +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) +static VALUE +create_encoding_table(interp) + VALUE interp; +{ + struct tcltkip *ptr = get_ip(interp); + volatile VALUE table = rb_hash_new(); + volatile VALUE encname = Qnil; + int i, objc; + Tcl_Obj **objv; + Tcl_Obj *enc_list; + + rb_secure(4); + + /* set 'binary' encoding */ + rb_hash_aset(table, ENCODING_NAME_BINARY, ENCODING_NAME_BINARY); + + /* get Tcl's encoding list */ + Tcl_GetEncodingNames(ptr->ip); + enc_list = Tcl_GetObjResult(ptr->ip); + Tcl_IncrRefCount(enc_list); + + if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) { + Tcl_DecrRefCount(enc_list); + rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names"); + } + + /* get encoding name and set it to table */ + for(i = 0; i < objc; i++) { + encname = rb_obj_freeze(rb_str_new2(Tcl_GetString(objv[i]))); + rb_hash_aset(table, encname, encname); + } + + Tcl_DecrRefCount(enc_list); + + rb_ivar_set(table, ID_at_interp, interp); + rb_ivar_set(interp, ID_encoding_table, table); + + return table; +} + +#else /* Tcl/Tk 7.x or 8.0 */ +static VALUE +create_encoding_table(interp) + VALUE interp; +{ + volatile VALUE table = rb_hash_new(); + rb_secure(4); + rb_ivar_set(interp, ID_encoding_table, table); + return table; +} +#endif +#endif + +static VALUE +ip_get_encoding_table(interp) + VALUE interp; +{ + volatile VALUE table = Qnil; + + table = rb_ivar_get(interp, ID_encoding_table); + + if (NIL_P(table)) { + /* initialize encoding_table */ + table = create_encoding_table(interp); + rb_define_singleton_method(table, "get_name", encoding_table_get_name, 1); + rb_define_singleton_method(table, "get_obj", encoding_table_get_obj, 1); + } + + return table; +} + + /*###############################################*/ /* @@ -8047,26 +9644,29 @@ struct dummy_TkMenuRef { char *dummy3; }; -#if 0 +#if 0 /* was available on Tk8.0 -- Tk8.4 */ EXTERN struct dummy_TkMenuRef *TkFindMenuReferences(Tcl_Interp*, char*); -#else -#define MENU_HASH_KEY "tkMenus" /* based on Tk8.0 - Tk8.5b1 */ +#else /* based on Tk8.0 -- Tk8.5.0 */ +#define MENU_HASH_KEY "tkMenus" #endif #endif static VALUE -ip_make_menu_embeddable(interp, menu_path) +ip_make_menu_embeddable_core(interp, argc, argv) VALUE interp; - VALUE menu_path; + int argc; + VALUE *argv; { #if TCL_MAJOR_VERSION >= 8 + volatile VALUE menu_path; struct tcltkip *ptr = get_ip(interp); struct dummy_TkMenuRef *menuRefPtr = NULL; XEvent event; Tcl_HashTable *menuTablePtr; Tcl_HashEntry *hashEntryPtr; + menu_path = argv[0]; StringValue(menu_path); #if 0 /* was available on Tk8.0 -- Tk8.4 */ @@ -8131,6 +9731,18 @@ ip_make_menu_embeddable(interp, menu_path) return interp; } +static VALUE +ip_make_menu_embeddable(interp, menu_path) + VALUE interp; + VALUE menu_path; +{ + VALUE argv[1]; + + argv[0] = menu_path; + return tk_funcall(ip_make_menu_embeddable_core, 1, argv, interp); +} + + /*###############################################*/ /*---- initialization ----*/ @@ -8152,6 +9764,22 @@ Init_tcltklib() /* --------------------------------------------------------------- */ +#ifdef RUBY_VM + rb_global_variable(&cRubyEncoding); + cRubyEncoding = rb_const_get(rb_cObject, rb_intern("Encoding")); + + ENCODING_INDEX_UTF8 = rb_enc_to_index(rb_utf8_encoding()); + ENCODING_INDEX_BINARY = rb_enc_find_index("binary"); +#endif + + rb_global_variable(&ENCODING_NAME_UTF8); + rb_global_variable(&ENCODING_NAME_BINARY); + + ENCODING_NAME_UTF8 = rb_obj_freeze(rb_str_new2("utf-8")); + ENCODING_NAME_BINARY = rb_obj_freeze(rb_str_new2("binary")); + + /* --------------------------------------------------------------- */ + rb_global_variable(&eTkCallbackReturn); rb_global_variable(&eTkCallbackBreak); rb_global_variable(&eTkCallbackContinue); @@ -8229,6 +9857,8 @@ Init_tcltklib() ID_at_enc = rb_intern("@encoding"); ID_at_interp = rb_intern("@interp"); + ID_encoding_name = rb_intern("encoding_name"); + ID_encoding_table = rb_intern("encoding_table"); ID_stop_p = rb_intern("stop?"); ID_alive_p = rb_intern("alive?"); @@ -8262,8 +9892,10 @@ Init_tcltklib() lib_evloop_abort_on_exc, 0); rb_define_module_function(lib, "mainloop_abort_on_exception=", lib_evloop_abort_on_exc_set, 1); - rb_define_module_function(lib, "set_eventloop_window_mode",set_eventloop_window_mode,1); - rb_define_module_function(lib, "get_eventloop_window_mode",get_eventloop_window_mode,0); + rb_define_module_function(lib, "set_eventloop_window_mode", + set_eventloop_window_mode, 1); + rb_define_module_function(lib, "get_eventloop_window_mode", + get_eventloop_window_mode, 0); rb_define_module_function(lib, "set_eventloop_tick",set_eventloop_tick,1); rb_define_module_function(lib, "get_eventloop_tick",get_eventloop_tick,0); rb_define_module_function(lib, "set_no_event_wait", set_no_event_wait, 1); @@ -8325,6 +9957,12 @@ Init_tcltklib() /* --------------------------------------------------------------- */ + rb_define_method(ip, "create_dummy_encoding_for_tk", + create_dummy_encoding_for_tk, 1); + rb_define_method(ip, "encoding_table", ip_get_encoding_table, 0); + + /* --------------------------------------------------------------- */ + rb_define_method(ip, "_get_variable", ip_get_variable, 2); rb_define_method(ip, "_get_variable2", ip_get_variable2, 3); rb_define_method(ip, "_set_variable", ip_set_variable, 3); @@ -8384,7 +10022,11 @@ Init_tcltklib() /* if ruby->nativethread-supprt and tcltklib->doen't, the following will cause link-error. */ +#ifdef RUBY_VM ruby_native_thread_p(); +#else + is_ruby_native_thread(); +#endif /* --------------------------------------------------------------- */ @@ -8405,6 +10047,11 @@ Init_tcltklib() } /* --------------------------------------------------------------- */ + + Tcl_ObjType_ByteArray = Tcl_GetObjType(Tcl_ObjTypeName_ByteArray); + Tcl_ObjType_String = Tcl_GetObjType(Tcl_ObjTypeName_String); + + /* --------------------------------------------------------------- */ } /* eof */ diff --git a/ext/tk/tkutil/tkutil.c b/ext/tk/tkutil/tkutil.c index cccb6e155..1781dd5e4 100644 --- a/ext/tk/tkutil/tkutil.c +++ b/ext/tk/tkutil/tkutil.c @@ -7,11 +7,20 @@ ************************************************/ -#define TKUTIL_RELEASE_DATE "2006-04-06" +#define TKUTIL_RELEASE_DATE "2008-03-29" -#include "ruby/ruby.h" +#include "ruby.h" + +#ifdef RUBY_VM /* Ruby 1.9 */ +/* #include "ruby/ruby.h" */ #include "ruby/signal.h" #include "ruby/st.h" +#else +/* #include "ruby.h" */ +#include "rubysig.h" +#include "version.h" +#include "st.h" +#endif static VALUE cMethod; @@ -25,6 +34,8 @@ static VALUE TK_None; static VALUE cCB_SUBST; static VALUE cSUBST_INFO; +static VALUE ENCODING_NAME_UTF8; /* for saving GC cost */ + static ID ID_split_tklist; static ID ID_toUTF8; static ID ID_fromUTF8; @@ -382,7 +393,7 @@ ary2list(ary, enc_flag, self) val = rb_funcall(cTclTkLib, ID_fromUTF8, 2, val, dst_enc); rb_ivar_set(val, ID_at_enc, dst_enc); } else { - rb_ivar_set(val, ID_at_enc, rb_str_new2("utf-8")); + rb_ivar_set(val, ID_at_enc, ENCODING_NAME_UTF8); } return val; } else { @@ -475,7 +486,7 @@ ary2list2(ary, enc_flag, self) val = rb_funcall(cTclTkLib, ID_fromUTF8, 2, val, dst_enc); rb_ivar_set(val, ID_at_enc, dst_enc); } else { - rb_ivar_set(val, ID_at_enc, rb_str_new2("utf-8")); + rb_ivar_set(val, ID_at_enc, ENCODING_NAME_UTF8); } return val; } else { @@ -780,7 +791,11 @@ get_eval_string_core(obj, enc_flag, self) return fromDefaultEnc_toUTF8(rb_str_new2(rb_id2name(SYM2ID(obj))), self); } } else { +#ifdef RUBY_VM + return rb_sym_to_s(obj); +#else return rb_str_new2(rb_id2name(SYM2ID(obj))); +#endif } case T_HASH: @@ -1485,6 +1500,7 @@ tkobj_path(self) return rb_ivar_get(self, ID_at_path); } + /*************************************/ /* release date */ const char tkutil_release_date[] = TKUTIL_RELEASE_DATE; @@ -1609,4 +1625,8 @@ Init_tkutil() rb_define_method(mTK, "num_or_str", tcl2rb_num_or_str, 1); /* --------------------- */ + rb_global_variable(&ENCODING_NAME_UTF8); + ENCODING_NAME_UTF8 = rb_obj_freeze(rb_str_new2("utf-8")); + + /* --------------------- */ } |