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 | 3024ffdc3a5fdb115de651edae9e3d7a335a6614 (patch) | |
tree | acfc67e481cd24c5e1ca2a344bd97e514fb26246 /ext/tk/lib/tk | |
parent | b62af05a98bc3ebbbca546270e7efa5abd3a17f5 (diff) |
* 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: svn+ssh://ci.ruby-lang.org/ruby/trunk@15848 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/tk/lib/tk')
-rw-r--r-- | ext/tk/lib/tk/autoload.rb | 19 | ||||
-rw-r--r-- | ext/tk/lib/tk/bindtag.rb | 83 | ||||
-rw-r--r-- | ext/tk/lib/tk/canvas.rb | 34 | ||||
-rw-r--r-- | ext/tk/lib/tk/canvastag.rb | 114 | ||||
-rw-r--r-- | ext/tk/lib/tk/encodedstr.rb | 84 | ||||
-rw-r--r-- | ext/tk/lib/tk/event.rb | 25 | ||||
-rw-r--r-- | ext/tk/lib/tk/font.rb | 697 | ||||
-rw-r--r-- | ext/tk/lib/tk/image.rb | 43 | ||||
-rw-r--r-- | ext/tk/lib/tk/itemconfig.rb | 107 | ||||
-rw-r--r-- | ext/tk/lib/tk/menu.rb | 27 | ||||
-rw-r--r-- | ext/tk/lib/tk/msgcat.rb | 6 | ||||
-rw-r--r-- | ext/tk/lib/tk/namespace.rb | 135 | ||||
-rw-r--r-- | ext/tk/lib/tk/optiondb.rb | 14 | ||||
-rw-r--r-- | ext/tk/lib/tk/root.rb | 8 | ||||
-rw-r--r-- | ext/tk/lib/tk/scale.rb | 21 | ||||
-rw-r--r-- | ext/tk/lib/tk/scrollbar.rb | 41 | ||||
-rw-r--r-- | ext/tk/lib/tk/spinbox.rb | 16 | ||||
-rw-r--r-- | ext/tk/lib/tk/text.rb | 34 | ||||
-rw-r--r-- | ext/tk/lib/tk/textmark.rb | 73 | ||||
-rw-r--r-- | ext/tk/lib/tk/texttag.rb | 89 | ||||
-rw-r--r-- | ext/tk/lib/tk/timer.rb | 17 | ||||
-rw-r--r-- | ext/tk/lib/tk/ttk_selector.rb | 9 | ||||
-rw-r--r-- | ext/tk/lib/tk/validation.rb | 16 | ||||
-rw-r--r-- | ext/tk/lib/tk/variable.rb | 486 | ||||
-rw-r--r-- | ext/tk/lib/tk/virtevent.rb | 77 | ||||
-rw-r--r-- | ext/tk/lib/tk/wm.rb | 476 |
26 files changed, 2131 insertions, 620 deletions
diff --git a/ext/tk/lib/tk/autoload.rb b/ext/tk/lib/tk/autoload.rb index f7037b4033..0773f7708d 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 9023a08e06..88c8367a88 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 4abc992027..fceadd5e9c 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 a5650ee68b..7feea1575c 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 797e514a4c..02de0b0d85 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 9884ca02e7..0042fcaa63 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 444118e6ae..4641d8a640 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 35e2c4e394..57f82cb812 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 a7885e74f3..dbc45a9e7c 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 e44f0e3ff1..8ba3156293 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 061e43fd89..162953f425 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 5bf6474c5b..9d2213ff51 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 6a7708ac53..186811d37d 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 4d83282448..7237b4c614 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 b97ed68072..bf2791ec55 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 66eadbd65f..521fc7e400 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 e7f223aea7..e372c58009 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 2ed1d30cf5..14b9be23f0 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 6ce52b58d7..72c1ce1ab4 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 8264d52938..792d544fe7 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 47f2b79350..3588f0c480 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 f89b5c76be..72ed637a38 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 0c5b5c61b9..1da38c776d 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 632f00cedf..f738a96ee7 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 d47e80aecd..ae31ac1f8f 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 1f432a3848..49dd4d73c2 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 |