From aff4ce9c77784a9663852102a717d0385f18a0ea Mon Sep 17 00:00:00 2001 From: nagai Date: Sat, 29 Mar 2008 05:25:45 +0000 Subject: * 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/branches/ruby_1_8@15849 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/tk/MANUAL_tcltklib.eng | 24 + ext/tk/MANUAL_tcltklib.eucj | 22 + ext/tk/README.1st | 13 +- ext/tk/README.tcltklib | 14 +- ext/tk/extconf.rb | 68 +- ext/tk/lib/multi-tk.rb | 197 +- ext/tk/lib/tcltk.rb | 2 +- ext/tk/lib/tk.rb | 1055 +++++++-- ext/tk/lib/tk/autoload.rb | 358 ++- ext/tk/lib/tk/bindtag.rb | 83 +- ext/tk/lib/tk/button.rb | 5 +- ext/tk/lib/tk/canvas.rb | 45 +- ext/tk/lib/tk/canvastag.rb | 114 +- ext/tk/lib/tk/checkbutton.rb | 9 +- ext/tk/lib/tk/composite.rb | 18 +- ext/tk/lib/tk/encodedstr.rb | 84 +- ext/tk/lib/tk/entry.rb | 6 +- ext/tk/lib/tk/event.rb | 48 +- ext/tk/lib/tk/font.rb | 724 +++++- ext/tk/lib/tk/frame.rb | 5 +- ext/tk/lib/tk/image.rb | 43 +- ext/tk/lib/tk/itemconfig.rb | 107 +- ext/tk/lib/tk/label.rb | 5 +- ext/tk/lib/tk/labelframe.rb | 8 +- ext/tk/lib/tk/listbox.rb | 5 +- ext/tk/lib/tk/macpkg.rb | 9 +- ext/tk/lib/tk/menu.rb | 80 +- ext/tk/lib/tk/menubar.rb | 2 +- ext/tk/lib/tk/menuspec.rb | 14 +- ext/tk/lib/tk/message.rb | 5 +- ext/tk/lib/tk/msgcat.rb | 6 +- ext/tk/lib/tk/namespace.rb | 135 +- ext/tk/lib/tk/optiondb.rb | 16 +- ext/tk/lib/tk/package.rb | 4 + ext/tk/lib/tk/panedwindow.rb | 9 +- ext/tk/lib/tk/radiobutton.rb | 9 +- ext/tk/lib/tk/root.rb | 37 +- ext/tk/lib/tk/scale.rb | 26 +- ext/tk/lib/tk/scrollbar.rb | 58 +- ext/tk/lib/tk/scrollbox.rb | 7 +- ext/tk/lib/tk/spinbox.rb | 22 +- ext/tk/lib/tk/text.rb | 136 +- ext/tk/lib/tk/textimage.rb | 10 +- ext/tk/lib/tk/textmark.rb | 102 +- ext/tk/lib/tk/texttag.rb | 110 +- ext/tk/lib/tk/textwindow.rb | 10 +- ext/tk/lib/tk/timer.rb | 17 +- ext/tk/lib/tk/toplevel.rb | 11 +- ext/tk/lib/tk/validation.rb | 16 + ext/tk/lib/tk/variable.rb | 488 ++-- ext/tk/lib/tk/virtevent.rb | 77 +- ext/tk/lib/tk/winpkg.rb | 18 +- ext/tk/lib/tk/wm.rb | 476 ++-- ext/tk/lib/tkextlib/SUPPORT_STATUS | 2 +- ext/tk/lib/tkextlib/blt/bitmap.rb | 21 +- ext/tk/lib/tkextlib/blt/busy.rb | 2 +- ext/tk/lib/tkextlib/blt/component.rb | 351 ++- ext/tk/lib/tkextlib/blt/dragdrop.rb | 48 + ext/tk/lib/tkextlib/blt/eps.rb | 2 +- ext/tk/lib/tkextlib/blt/tabset.rb | 77 +- ext/tk/lib/tkextlib/blt/tile/button.rb | 2 +- ext/tk/lib/tkextlib/blt/tile/checkbutton.rb | 2 +- ext/tk/lib/tkextlib/blt/tile/frame.rb | 2 +- ext/tk/lib/tkextlib/blt/tile/label.rb | 2 +- ext/tk/lib/tkextlib/blt/tile/radiobutton.rb | 2 +- ext/tk/lib/tkextlib/blt/tile/scrollbar.rb | 2 +- ext/tk/lib/tkextlib/blt/tile/toplevel.rb | 2 +- ext/tk/lib/tkextlib/blt/tree.rb | 341 ++- ext/tk/lib/tkextlib/blt/treeview.rb | 197 +- ext/tk/lib/tkextlib/blt/vector.rb | 37 +- ext/tk/lib/tkextlib/blt/watch.rb | 28 +- ext/tk/lib/tkextlib/bwidget/button.rb | 2 +- ext/tk/lib/tkextlib/bwidget/buttonbox.rb | 20 +- ext/tk/lib/tkextlib/bwidget/combobox.rb | 8 +- ext/tk/lib/tkextlib/bwidget/dialog.rb | 26 +- ext/tk/lib/tkextlib/bwidget/entry.rb | 2 +- ext/tk/lib/tkextlib/bwidget/label.rb | 2 +- ext/tk/lib/tkextlib/bwidget/labelentry.rb | 2 +- ext/tk/lib/tkextlib/bwidget/labelframe.rb | 8 +- ext/tk/lib/tkextlib/bwidget/listbox.rb | 34 +- ext/tk/lib/tkextlib/bwidget/mainframe.rb | 48 +- ext/tk/lib/tkextlib/bwidget/messagedlg.rb | 5 +- ext/tk/lib/tkextlib/bwidget/notebook.rb | 24 +- ext/tk/lib/tkextlib/bwidget/pagesmanager.rb | 16 +- ext/tk/lib/tkextlib/bwidget/panedwindow.rb | 8 +- ext/tk/lib/tkextlib/bwidget/panelframe.rb | 8 +- ext/tk/lib/tkextlib/bwidget/progressdlg.rb | 4 + ext/tk/lib/tkextlib/bwidget/scrollableframe.rb | 8 +- ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb | 8 +- ext/tk/lib/tkextlib/bwidget/selectcolor.rb | 28 + ext/tk/lib/tkextlib/bwidget/selectfont.rb | 7 +- ext/tk/lib/tkextlib/bwidget/spinbox.rb | 2 +- ext/tk/lib/tkextlib/bwidget/statusbar.rb | 8 +- ext/tk/lib/tkextlib/bwidget/titleframe.rb | 8 +- ext/tk/lib/tkextlib/bwidget/tree.rb | 34 +- ext/tk/lib/tkextlib/bwidget/widget.rb | 8 +- ext/tk/lib/tkextlib/itcl/incr_tcl.rb | 12 +- ext/tk/lib/tkextlib/itk/incr_tk.rb | 44 +- ext/tk/lib/tkextlib/iwidgets/calendar.rb | 17 + ext/tk/lib/tkextlib/iwidgets/checkbox.rb | 16 +- ext/tk/lib/tkextlib/iwidgets/entryfield.rb | 17 + ext/tk/lib/tkextlib/iwidgets/hierarchy.rb | 52 +- ext/tk/lib/tkextlib/iwidgets/notebook.rb | 11 +- ext/tk/lib/tkextlib/iwidgets/radiobox.rb | 11 +- ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb | 10 +- ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb | 5 + ext/tk/lib/tkextlib/iwidgets/selectionbox.rb | 2 +- ext/tk/lib/tkextlib/iwidgets/selectiondialog.rb | 2 +- ext/tk/lib/tkextlib/iwidgets/spinner.rb | 17 + ext/tk/lib/tkextlib/iwidgets/tabnotebook.rb | 16 +- ext/tk/lib/tkextlib/iwidgets/tabset.rb | 44 + ext/tk/lib/tkextlib/tcllib/autoscroll.rb | 2 +- ext/tk/lib/tkextlib/tcllib/ctext.rb | 2 +- ext/tk/lib/tkextlib/tcllib/datefield.rb | 2 +- ext/tk/lib/tkextlib/tcllib/ico.rb | 6 +- ext/tk/lib/tkextlib/tcllib/ip_entry.rb | 2 +- ext/tk/lib/tkextlib/tcllib/plotchart.rb | 77 +- ext/tk/lib/tkextlib/tcllib/tkpiechart.rb | 14 +- ext/tk/lib/tkextlib/tile.rb | 217 +- ext/tk/lib/tkextlib/tile/sizegrip.rb | 4 + ext/tk/lib/tkextlib/tile/style.rb | 191 +- ext/tk/lib/tkextlib/tile/tbutton.rb | 7 +- ext/tk/lib/tkextlib/tile/tcheckbutton.rb | 8 +- ext/tk/lib/tkextlib/tile/tcombobox.rb | 3 + ext/tk/lib/tkextlib/tile/tentry.rb | 7 +- ext/tk/lib/tkextlib/tile/tframe.rb | 7 +- ext/tk/lib/tkextlib/tile/tlabel.rb | 7 +- ext/tk/lib/tkextlib/tile/tlabelframe.rb | 8 +- ext/tk/lib/tkextlib/tile/tmenubutton.rb | 12 +- ext/tk/lib/tkextlib/tile/tnotebook.rb | 3 + ext/tk/lib/tkextlib/tile/tpaned.rb | 12 +- ext/tk/lib/tkextlib/tile/tprogressbar.rb | 3 + ext/tk/lib/tkextlib/tile/tradiobutton.rb | 8 +- ext/tk/lib/tkextlib/tile/treeview.rb | 133 +- ext/tk/lib/tkextlib/tile/tscale.rb | 7 +- ext/tk/lib/tkextlib/tile/tscrollbar.rb | 28 +- ext/tk/lib/tkextlib/tile/tseparator.rb | 3 + ext/tk/lib/tkextlib/tkDND/tkdnd.rb | 16 + ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb | 17 +- ext/tk/lib/tkextlib/tktable/tktable.rb | 167 +- ext/tk/lib/tkextlib/tktrans/tktrans.rb | 4 +- ext/tk/lib/tkextlib/treectrl/tktreectrl.rb | 233 +- ext/tk/lib/tkextlib/version.rb | 2 +- ext/tk/lib/tkextlib/vu/pie.rb | 73 +- ext/tk/lib/tkextlib/vu/spinbox.rb | 2 +- ext/tk/lib/tkextlib/winico/winico.rb | 49 +- ext/tk/sample/binstr_usage.rb | 12 +- ext/tk/sample/demos-en/arrow.rb | 18 +- ext/tk/sample/demos-en/bind.rb | 9 +- ext/tk/sample/demos-en/ctext.rb | 45 +- ext/tk/sample/demos-en/entry3.rb | 2 +- ext/tk/sample/demos-en/hello | 6 +- ext/tk/sample/demos-en/hscale.rb | 2 +- ext/tk/sample/demos-en/items.rb | 9 +- ext/tk/sample/demos-en/patch_1.1c1 | 93 - ext/tk/sample/demos-en/pendulum.rb | 35 +- ext/tk/sample/demos-en/rolodex-j | 323 --- ext/tk/sample/demos-en/search.rb | 7 +- ext/tk/sample/demos-en/style.rb | 34 +- ext/tk/sample/demos-en/textpeer.rb | 72 + ext/tk/sample/demos-en/twind.rb | 6 +- ext/tk/sample/demos-en/vscale.rb | 1 - ext/tk/sample/demos-en/widget | 32 +- ext/tk/sample/demos-jp/anilabel.rb | 1 + ext/tk/sample/demos-jp/aniwave.rb | 1 + ext/tk/sample/demos-jp/arrow.rb | 19 +- ext/tk/sample/demos-jp/bind.rb | 10 +- ext/tk/sample/demos-jp/bitmap.rb | 1 + ext/tk/sample/demos-jp/button.rb | 1 + ext/tk/sample/demos-jp/check.rb | 1 + ext/tk/sample/demos-jp/check2.rb | 1 + ext/tk/sample/demos-jp/clrpick.rb | 1 + ext/tk/sample/demos-jp/colors.rb | 1 + ext/tk/sample/demos-jp/cscroll.rb | 1 + ext/tk/sample/demos-jp/ctext.rb | 46 +- ext/tk/sample/demos-jp/dialog1.rb | 1 + ext/tk/sample/demos-jp/dialog2.rb | 1 + ext/tk/sample/demos-jp/entry1.rb | 1 + ext/tk/sample/demos-jp/entry2.rb | 1 + ext/tk/sample/demos-jp/entry3.rb | 1 + ext/tk/sample/demos-jp/filebox.rb | 1 + ext/tk/sample/demos-jp/floor.rb | 1 + ext/tk/sample/demos-jp/floor2.rb | 1 + ext/tk/sample/demos-jp/form.rb | 1 + ext/tk/sample/demos-jp/goldberg.rb | 1 + ext/tk/sample/demos-jp/hello | 1 + ext/tk/sample/demos-jp/hscale.rb | 2 +- ext/tk/sample/demos-jp/icon.rb | 1 + ext/tk/sample/demos-jp/image1.rb | 1 + ext/tk/sample/demos-jp/image2.rb | 1 + ext/tk/sample/demos-jp/image3.rb | 1 + ext/tk/sample/demos-jp/items.rb | 10 +- ext/tk/sample/demos-jp/ixset2 | 1 + ext/tk/sample/demos-jp/label.rb | 1 + ext/tk/sample/demos-jp/labelframe.rb | 2 + ext/tk/sample/demos-jp/menu.rb | 1 + ext/tk/sample/demos-jp/menu84.rb | 1 + ext/tk/sample/demos-jp/menu8x.rb | 1 + ext/tk/sample/demos-jp/menubu.rb | 1 + ext/tk/sample/demos-jp/msgbox.rb | 1 + ext/tk/sample/demos-jp/paned1.rb | 2 + ext/tk/sample/demos-jp/paned2.rb | 2 + ext/tk/sample/demos-jp/pendulum.rb | 36 +- ext/tk/sample/demos-jp/plot.rb | 7 +- ext/tk/sample/demos-jp/puzzle.rb | 1 + ext/tk/sample/demos-jp/radio.rb | 1 + ext/tk/sample/demos-jp/radio2.rb | 2 + ext/tk/sample/demos-jp/radio3.rb | 2 + ext/tk/sample/demos-jp/rolodex-j | 1 + ext/tk/sample/demos-jp/ruler.rb | 1 + ext/tk/sample/demos-jp/sayings.rb | 1 + ext/tk/sample/demos-jp/search.rb | 8 +- ext/tk/sample/demos-jp/spin.rb | 2 + ext/tk/sample/demos-jp/states.rb | 1 + ext/tk/sample/demos-jp/style.rb | 37 +- ext/tk/sample/demos-jp/tcolor | 1 + ext/tk/sample/demos-jp/text.rb | 1 + ext/tk/sample/demos-jp/textpeer.rb | 78 + ext/tk/sample/demos-jp/twind.rb | 7 +- ext/tk/sample/demos-jp/twind2.rb | 1 + ext/tk/sample/demos-jp/unicodeout.rb | 2 + ext/tk/sample/demos-jp/vscale.rb | 3 +- ext/tk/sample/demos-jp/widget | 52 +- ext/tk/sample/encstr_usage.rb | 5 +- ext/tk/sample/irbtkw.rbw | 24 +- ext/tk/sample/tcltklib/sample2.rb | 2 +- ext/tk/sample/tkextlib/tile/demo.rb | 37 +- .../sample/tkextlib/tile/themes/blue/pkgIndex.tcl | 2 +- ext/tk/sample/tkextlib/tile/themes/kroc.rb | 30 +- ext/tk/sample/tkextlib/vu/canvSticker2.rb | 12 +- ext/tk/sample/tkrttimer.rb | 13 +- ext/tk/sample/tksleep_sample.rb | 29 + ext/tk/sample/ttk_wrapper.rb | 154 ++ ext/tk/stubs.c | 78 +- ext/tk/tcltklib.c | 2367 ++++++++++++++++++-- ext/tk/tkutil/extconf.rb | 1 + ext/tk/tkutil/tkutil.c | 269 ++- 237 files changed, 9440 insertions(+), 2690 deletions(-) delete mode 100644 ext/tk/sample/demos-en/patch_1.1c1 delete mode 100644 ext/tk/sample/demos-en/rolodex-j create mode 100644 ext/tk/sample/demos-en/textpeer.rb create mode 100644 ext/tk/sample/demos-jp/textpeer.rb create mode 100644 ext/tk/sample/tksleep_sample.rb create mode 100644 ext/tk/sample/ttk_wrapper.rb (limited to 'ext/tk') diff --git a/ext/tk/MANUAL_tcltklib.eng b/ext/tk/MANUAL_tcltklib.eng index 1db61f228e..6fa775b7de 100644 --- a/ext/tk/MANUAL_tcltklib.eng +++ b/ext/tk/MANUAL_tcltklib.eng @@ -125,7 +125,24 @@ module TclTklib : Tcl7.6 doesn't have this flag. So PARSE_VARNAME is : defined as 0. + module TclTkLib::RELEASE_TYPE + : Defines release type number of Tcl/Tk + + ALPHA + : ALPHA release + + BETA + : BETA release + + FINAL + : FINAL release + [module methods] + get_version() + : return an array of major, minor, release-type number, + : number, release-type name, and patchlevel of current + : Tcl/Tk library. + mainloop(check_root = true) : Starts the eventloop. If 'check_root' is true, this method : doesn't return when a root widget exists. @@ -431,6 +448,10 @@ class TclTkIp : slave interpreter, same to the TclTkLib module method with : the same name. + encoding_table + : For Ruby m17n. Return encoding relation table between Ruby's + : Encoding object and Tcl's encoding name. + class TkCallbackBreak < StandardError class TkCallbackContinue < StandardError : They are exception classes to break or continue the Tk callback @@ -441,5 +462,8 @@ class TkCallbackContinue < StandardError : If raise TkCallbackContinue, returns 'continue' code (Then the Tk : interpreter will break the operateion for the current bindtag and : starts the operation for the next buindtag for the current event). + : However, current tcltklib supports Ruby's 'break' and 'next' to + : get the same effect. That is, those classes are obsolete. Those + : exist for backward compatibility. (eof) diff --git a/ext/tk/MANUAL_tcltklib.eucj b/ext/tk/MANUAL_tcltklib.eucj index 5dd36726ba..7df42997b4 100644 --- a/ext/tk/MANUAL_tcltklib.eucj +++ b/ext/tk/MANUAL_tcltklib.eucj @@ -221,7 +221,23 @@ require "tcltklib" : ¤«¤éÃê½Ð¤µ¤ì¤ë¤Ï¤º¤Ç¤¢¤ë¤«¤é¡¤index_name °ú¿ô¤Ï nil ¤È : ¤»¤Í¤Ð¤Ê¤é¤Ê¤¤¡¥ + ¥â¥¸¥å¡¼¥ë TclTkLib::RELEASE_TYPE + : Tcl/Tk ¤Î¥ê¥ê¡¼¥¹¥¿¥¤¥×ÈÖ¹æ¤ÎÄêµÁ + + Äê¿ô ALPHA + : ALPHA ¥ê¥ê¡¼¥¹ + + Äê¿ô BETA + : BETA ¥ê¥ê¡¼¥¹ + + Äê¿ô FINAL + : FINAL ¥ê¥ê¡¼¥¹ + ¥â¥¸¥å¡¼¥ë¥á¥½¥Ã¥É + get_version() + : Tcl/Tk ¤Î major, minor, release-type ÈÖ¹æ, release-type ̾, + : patchlevel ¤òÇÛÎó¤Ë¤·¤ÆÊÖ¤¹¡¥ + mainloop(check_root = true) : ¥¤¥Ù¥ó¥È¥ë¡¼¥×¤òµ¯Æ°¤¹¤ë¡¥check_root ¤¬ true ¤Ç¤¢¤ì¤Ð¡¤ : root widget ¤¬Â¸ºß¤¹¤ë¸Â¤ê¡¤¤³¤Î¥á¥½¥Ã¥É¤Ï½ªÎ»¤·¤Ê¤¤¡¥ @@ -543,6 +559,9 @@ require "tcltklib" : ¥¹¥ì¡¼¥Ö IP ¤Î¾ì¹ç¤Ë¤ÏÃͤÎÀßÄ꤬µö¤µ¤ì¤Ê¤¤ (̵»ë¤µ¤ì¤ë)¡¥ : ¤½¤ì°Ê³°¤ÎÅÀ¤Ç¤Ï°ú¿ô¤ò´Þ¤á¤Æ TclTkLib ¤ÎƱ̾¥á¥½¥Ã¥É¤ËƱ¤¸¡¥ + encoding_table + : Ruby m17n ÍÑ¤Ë Ruby ¤È Tk ¤È¤Î´Ö¤Î encoding Âбþɽ¤òÊÖ¤¹¡¥ + ¥¯¥é¥¹ TkCallbackBreak < StandardError ¥¯¥é¥¹ TkCallbackContinue < StandardError : ¤³¤ì¤é¤Ï¥¤¥Ù¥ó¥È¥³¡¼¥ë¥Ð¥Ã¥¯¤Ë¤ª¤¤¤Æ¡¤¥³¡¼¥ë¥Ð¥Ã¥¯½èÍý¤òŬÀÚ¤ËÃæ @@ -553,5 +572,8 @@ require "tcltklib" : ¥É¤òÊÖ¤¹É¬Íפ¬¤¢¤ë¡¥Ruby ¤Î¼ê³¤­¤¬ÉáÄ̤ËÃͤòÊÖ¤¹¤Î¤Ç¤Ï¡¤¤½¤ì¤¬Éá : Ä̤ÎÌá¤êÃͤǤ¢¤ë¤Î¤«Èݤ«¤ò¶èÊ̤¬¤Ç¤­¤Ê¤¤¤¿¤á¡¤Î㳰ȯÀ¸¤òÍøÍѤ·¤¿ : ¼ÂÁõ¤ò¹Ô¤Ã¤Æ¤¤¤ë¡¥ + : ¤¿¤À¤·¸½ºß¤Ç¤Ï¡¤¥³¡¼¥ë¥Ð¥Ã¥¯¼ê³¤­¤ò Ruby ¤Î break, next ¤Ç½ªÎ»¤¹ + : ¤ë¤³¤È¤ÇƱÅù¤Î·ë²Ì¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤ë¤è¤¦¤Ë¤Ê¤Ã¤Æ¤¤¤ë¡¥¤½¤ì¤æ¤¨¡¤ + : ¤³¤ì¤é¤ÏɬÍפʤ¤¤â¤Î¤Ç¤Ï¤¢¤ë¤¬¡¤¸ß´¹À­¤Î¤¿¤á¤Ë»Ä¤·¤Æ¤¢¤ë¡¥ (eof) diff --git a/ext/tk/README.1st b/ext/tk/README.1st index df6c819d26..fce5b0242b 100644 --- a/ext/tk/README.1st +++ b/ext/tk/README.1st @@ -1,7 +1,6 @@ If you want to use Ruby/Tk (tk.rb and so on), you must have tcltklib.so -which is working correctly. If you fail to call 'require "tcltklib"', -you may not have tcltklib.so. When you have some troubles on compiling -tcltklib, please read README files on tcltklib. +which is working correctly. When you have some troubles on compiling, +please read README.tcltklib and README.ActiveTcl. Even if there is a tcltklib.so on your Ruby library directry, it will not work without Tcl/Tk libraries (e.g. libtcl8.4.so) on your environment. You must also check that your Tcl/Tk is installed properly. @@ -9,11 +8,9 @@ You must also check that your Tcl/Tk is installed properly. -------------------------------------------- ( the following is written in EUC-JP ) -Ruby/Tk (tk.rb ¤Ê¤É) ¤ò»È¤¤¤¿¤¤¾ì¹ç¤Ë¤Ï¡¤tcltklib.so ¤¬Àµ¤·¤¯Æ°¤¤¤Æ -¤¤¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó¡¥¤â¤· 'require "tcltklib"' ¤Ë¼ºÇÔ¤¹¤ë¤è¤¦¤Ê¤é¡¤ -tcltklib.so ¤¬¥¤¥ó¥¹¥È¡¼¥ë¤µ¤ì¤Æ¤¤¤Ê¤¤¤Î¤«¤â¤·¤ì¤Þ¤»¤ó¡¥tcltklib ¤Î -¥³¥ó¥Ñ¥¤¥ë»þ¤Ë²¿¤«ÌäÂ꤬À¸¤¸¤Æ¤¤¤ë¾ì¹ç¤Ï¡¤tcltklib ¤Î README ¥Õ¥¡¥¤¥ë -¤ò¸«¤Æ¤¯¤À¤µ¤¤¡¥ +Ruby/Tk (tk.rb ¤Ê¤É) ¤ò»È¤¤¤¿¤¤¾ì¹ç¤Ë¤Ï¡¤tcltklib.so ¤¬Àµ¤·¤¯Æ°¤¤¤Æ¤¤¤Ê +¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó¡¥¥³¥ó¥Ñ¥¤¥ë»þ¤Ë²¿¤«ÌäÂ꤬À¸¤¸¤¿¾ì¹ç¤Ï¡¤README.tcltklib +¤ä README.ActiveTcl ¤ò¸«¤Æ¤¯¤À¤µ¤¤¡¥ ¤¿¤È¤¨ Ruby ¤Î¥é¥¤¥Ö¥é¥ê¥Ç¥£¥ì¥¯¥È¥ê¤Ë tcltklib.so ¤¬Â¸ºß¤·¤Æ¤¤¤¿¤È¤·¤Æ ¤â¡¤¼Â¹Ô´Ä¶­¤Ë Tcl/Tk ¥é¥¤¥Ö¥é¥ê (libtcl8.4.so ¤Ê¤É) ¤¬¤Ê¤±¤ì¤Ðµ¡Ç½¤·¤Þ ¤»¤ó¡¥Tcl/Tk ¤¬Àµ¤·¤¯¥¤¥ó¥¹¥È¡¼¥ë¤µ¤ì¤Æ¤¤¤ë¤«¤â¥Á¥§¥Ã¥¯¤·¤Æ¤¯¤À¤µ¤¤¡¥ diff --git a/ext/tk/README.tcltklib b/ext/tk/README.tcltklib index e939ba1f51..b94d778104 100644 --- a/ext/tk/README.tcltklib +++ b/ext/tk/README.tcltklib @@ -16,18 +16,18 @@ some or all of the following options. --with-tk-dir= equal to "--with-tk-include=/include --with-tk-lib=/lib" - --with-tcl-include= the directry containts 'tcl.h' - --with-tk-include= the directry containts 'tk.h' + --with-tcl-include= the directry contains 'tcl.h' + --with-tk-include= the directry contains 'tk.h' - --with-tcl-lib= the directry containts 'libtcl.so' - --with-tk-lib= the directry containts 'libtk.so' + --with-tcl-lib= the directry contains 'libtcl.so' + --with-tk-lib= the directry contains 'libtk.so' --enable-mac-tcltk-framework (MacOS X) use Tcl/Tk framework (Obsolete. Please use '--enable-tcltk-framework'.) --enable-tcltk-framework use Tcl/Tk framework - --with-tcltk-framework= the directory containts Tcl/Tk framework; + --with-tcltk-framework= the directory contains Tcl/Tk framework; "/Tcl.framework" and "/Tk.framework". When this option is given, it is assumed that --enable-tcltk-framework option is given also. @@ -46,8 +46,8 @@ some or all of the following options. --with-X11-dir= equal to "--with-X11-include=/include --with-X11-lib=/lib" - --with-X11-include= the directry contains X11 header files - --with-X11-lib= the directry contains X11 libraries + --with-X11-include= the directry contais X11 header files + --with-X11-lib= the directry contais X11 libraries If you forgot to give the options when do 'configure' on toplevel diff --git a/ext/tk/extconf.rb b/ext/tk/extconf.rb index 5ed86a8b76..cb7621fbd4 100644 --- a/ext/tk/extconf.rb +++ b/ext/tk/extconf.rb @@ -2,7 +2,8 @@ require 'mkmf' -is_win32 = (/mswin32|mingw|cygwin|bccwin32/ =~ RUBY_PLATFORM) +#is_win32 = (/mswin32|mingw|cygwin|bccwin32/ =~ RUBY_PLATFORM) +is_win32 = (/mswin|mingw|cygwin|bccwin|wince/ =~ RUBY_PLATFORM) #is_macosx = (/darwin/ =~ RUBY_PLATFORM) def find_framework(tcl_hdr, tk_hdr) @@ -39,9 +40,13 @@ unless is_win32 have_library("m", "log") end -dir_config("tk") -dir_config("tcl") -dir_config("X11") +tk_idir, tk_ldir = dir_config("tk") +tcl_idir, tcl_ldir = dir_config("tcl") +x11_idir, x11_ldir = dir_config("X11") + +tk_ldir2 = with_config("tk-lib") +tcl_ldir2 = with_config("tcl-lib") +x11_ldir2 = with_config("X11-lib") tklib = with_config("tklib") tcllib = with_config("tcllib") @@ -49,8 +54,9 @@ stubs = enable_config("tcltk_stubs") || with_config("tcltk_stubs") use_X = with_config("X11", (! is_win32)) -def find_tcl(tcllib, stubs) - paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"] +def find_tcl(tcllib, stubs, *opt_paths) + default_paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"] + paths = opt_paths.compact.concat(default_paths) if stubs func = "Tcl_InitStubs" lib = "tclstub" @@ -60,20 +66,23 @@ def find_tcl(tcllib, stubs) end if tcllib find_library(tcllib, func, *paths) - elsif find_library(lib, func, *paths) - true else - %w[8.5 8.4 8.3 8.2 8.1 8.0 7.6].find { |ver| + %w[8.6 8.5 8.4 8.3 8.2 8.1 8.0 7.6].find { |ver| find_library("#{lib}#{ver}", func, *paths) or find_library("#{lib}#{ver.delete('.')}", func, *paths) or + find_library("#{lib}#{ver}g", func, *paths) or + find_library("#{lib}#{ver.delete('.')}g", func, *paths) or find_library("tcl#{ver}", func, *paths) or - find_library("tcl#{ver.delete('.')}", func, *paths) - } + find_library("tcl#{ver.delete('.')}", func, *paths) or + find_library("tcl#{ver}g", func, *paths) or + find_library("tcl#{ver.delete('.')}g", func, *paths) + } || find_library(lib, func, *paths) end end -def find_tk(tklib, stubs) - paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"] +def find_tk(tklib, stubs, *opt_paths) + default_paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"] + paths = opt_paths.compact.concat(default_paths) if stubs func = "Tk_InitStubs" lib = "tkstub" @@ -83,18 +92,27 @@ def find_tk(tklib, stubs) end if tklib find_library(tklib, func, *paths) - elsif find_library(lib, func, *paths) - true else - %w[8.5 8.4 8.3 8.2 8.1 8.0 4.2].find { |ver| + %w[8.6 8.5 8.4 8.3 8.2 8.1 8.0 4.2].find { |ver| find_library("#{lib}#{ver}", func, *paths) or find_library("#{lib}#{ver.delete('.')}", func, *paths) or + find_library("#{lib}#{ver}g", func, *paths) or + find_library("#{lib}#{ver.delete('.')}g", func, *paths) or find_library("tk#{ver}", func, *paths) or - find_library("tk#{ver.delete('.')}", func, *paths) - } + find_library("tk#{ver.delete('.')}", func, *paths) or + find_library("tk#{ver}g", func, *paths) or + find_library("tk#{ver.delete('.')}g", func, *paths) + } || find_library(lib, func, *paths) end end +def find_X11(*opt_paths) + default_paths = + [ "/usr/X11/lib", "/usr/lib/X11", "/usr/X11R6/lib", "/usr/openwin/lib" ] + paths = opt_paths.compact.concat(default_paths) + find_library("X11", "XOpenDisplay", *paths) +end + def pthread_check() tcl_major_ver = nil tcl_minor_ver = nil @@ -273,13 +291,11 @@ EOF end end -if tcltk_framework || - (have_header("tcl.h") && have_header("tk.h") && - ( !use_X || find_library("X11", "XOpenDisplay", - "/usr/X11/lib", "/usr/lib/X11", - "/usr/X11R6/lib", "/usr/openwin/lib")) && - find_tcl(tcllib, stubs) && - find_tk(tklib, stubs)) +if have_header("tcl.h") && have_header("tk.h") && + ( tcltk_framework || + ( ( !use_X || find_X11(x11_ldir2, x11_ldir) ) && + find_tcl(tcllib, stubs, tcl_ldir2, tcl_ldir) && + find_tk(tklib, stubs, tk_ldir2, tk_ldir) ) ) $CPPFLAGS += ' -DUSE_TCL_STUBS -DUSE_TK_STUBS' if stubs $CPPFLAGS += ' -D_WIN32' if /cygwin/ =~ RUBY_PLATFORM @@ -307,6 +323,8 @@ if tcltk_framework || $INSTALLFILES << ["lib/tkextlib/SUPPORT_STATUS", "$(RUBYLIBDIR)", "lib"] # create + $defs << %[-DRUBY_VERSION=\\"#{RUBY_VERSION}\\"] + $defs << %[-DRUBY_RELEASE_DATE=\\"#{RUBY_RELEASE_DATE}\\"] create_makefile("tcltklib") end end diff --git a/ext/tk/lib/multi-tk.rb b/ext/tk/lib/multi-tk.rb index 78ed1aa6ee..fd9a863888 100644 --- a/ext/tk/lib/multi-tk.rb +++ b/ext/tk/lib/multi-tk.rb @@ -114,7 +114,14 @@ MultiTkIp_OK.freeze class MultiTkIp BASE_DIR = File.dirname(__FILE__) - @@SLAVE_IP_ID = ['slave'.freeze, '0'.taint].freeze + WITH_RUBY_VM = Object.const_defined?(:VM) && ::VM.class == Class + WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class + + (@@SLAVE_IP_ID = ['slave'.freeze, '0'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } @@IP_TABLE = {}.taint unless defined?(@@IP_TABLE) @@ -126,14 +133,18 @@ class MultiTkIp unless defined?(@@TK_CMD_TBL) @@TK_CMD_TBL = Object.new.taint - @@TK_CMD_TBL.instance_variable_set('@tbl', {}.taint) + # @@TK_CMD_TBL.instance_variable_set('@tbl', {}.taint) + @@TK_CMD_TBL.instance_variable_set('@tbl', Hash.new{|hash,key| + fail IndexError, + "unknown command ID '#{key}'" + }.taint) class << @@TK_CMD_TBL allow = [ - '__send__', '__id__', 'freeze', 'inspect', 'kind_of?', + '__send__', '__id__', 'freeze', 'inspect', 'kind_of?', 'object_id', '[]', '[]=', 'delete', 'each', 'has_key?' ] - instance_methods.each{|m| undef_method(m) unless allow.index(m)} + instance_methods.each{|m| undef_method(m) unless allow.index(m.to_s)} def kind_of?(klass) @tbl.kind_of?(klass) @@ -206,7 +217,7 @@ class MultiTkIp def initialize(ip, cmd) @ip = ip @cmd = cmd - freeze + self.freeze end attr_reader :ip, :cmd def inspect @@ -573,7 +584,11 @@ class MultiTkIp # raise exception begin bt = _toUTF8(e.backtrace.join("\n")) - bt.instance_variable_set(:@encoding, 'utf-8') + if MultiTkIp::WITH_ENCODING + bt.force_encoding('utf-8') + else + bt.instance_variable_set(:@encoding, 'utf-8') + end rescue Exception bt = e.backtrace.join("\n") end @@ -695,6 +710,11 @@ class MultiTkIp ###################################### + unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD + ### Ruby 1.9 !!!!!!!!!!!!!!!!!!!!!!!!!! + RUN_EVENTLOOP_ON_MAIN_THREAD = false + end + if self.const_defined? :DEFAULT_MASTER_NAME name = DEFAULT_MASTER_NAME.to_s else @@ -723,7 +743,41 @@ class MultiTkIp fail ArgumentError, "expecting a Hash object for the 2nd argument" end - @interp = TclTkIp.new(name, _keys2opts(keys)) + if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!! + @interp = TclTkIp.new(name, _keys2opts(keys)) + else ### Ruby 1.9 !!!!!!!!!!! + @interp_thread = Thread.new{ + current = Thread.current + current[:interp] = interp = TclTkIp.new(name, _keys2opts(keys)) + #sleep + current[:mutex] = mutex = Mutex.new + current[:root_check] = cond_var = ConditionVariable.new + + begin + current[:status] = interp.mainloop(true) + rescue Exception=>e + current[:status] = e + ensure + mutex.synchronize{ cond_var.broadcast } + end + current[:status] = interp.mainloop(false) + } + until @interp_thread[:interp] + Thread.pass + end + # INTERP_THREAD.run + @interp = @interp_thread[:interp] + + def self.mainloop(check_root = true) + begin + TclTkLib.set_eventloop_window_mode(true) + @interp_thread.value + ensure + TclTkLib.set_eventloop_window_mode(false) + end + end + end + @ip_name = nil @callback_status = [].taint @@ -853,22 +907,26 @@ class MultiTkIp Thread.new{ current = Thread.current loop { - mtx, ret, table, script = @init_ip_env_queue.deq - begin + mtx, cond, ret, table, script = @init_ip_env_queue.deq + begin ret[0] = table.each{|tg, ip| ip._init_ip_env(script) } rescue Exception => e ret[0] = e ensure - mtx.unlock + mtx.synchronize{ cond.signal } end + mtx = cond = ret = table = script = nil # clear variables for GC } } def self.__init_ip_env__(table, script) ret = [] - mtx = Mutex.new.lock - @init_ip_env_queue.enq([mtx, ret, table, script]) - mtx.lock + mtx = (Thread.current[:MultiTk_ip_Mutex] ||= Mutex.new) + cond = (Thread.current[:MultiTk_ip_CondVar] ||= ConditionVariable.new) + mtx.synchronize{ + @init_ip_env_queue.enq([mtx, cond, ret, table, script]) + cond.wait(mtx) + } if ret[0].kind_of?(Exception) raise ret[0] else @@ -947,9 +1005,11 @@ class MultiTkIp private :_parse_slaveopts def _create_slave_ip_name - name = @@SLAVE_IP_ID.join('') - @@SLAVE_IP_ID[1].succ! - name.freeze + @@SLAVE_IP_ID.mutex.synchronize{ + name = @@SLAVE_IP_ID.join('') + @@SLAVE_IP_ID[1].succ! + name.freeze + } end private :_create_slave_ip_name @@ -1206,7 +1266,20 @@ class MultiTkIp if safeip == nil # create master-ip - @interp = TclTkIp.new(name, _keys2opts(tk_opts)) + unless WITH_RUBY_VM + @interp = TclTkIp.new(name, _keys2opts(tk_opts)) + else ### Ruby 1.9 !!!!!!!!!!! + @interp_thread = Thread.new{ + Thread.current[:interp] = interp = TclTkIp.new(name, _keys2opts(tk_opts)) + #sleep + TclTkLib.mainloop(true) + } + until @interp_thread[:interp] + Thread.pass + end + # INTERP_THREAD.run + @interp = @interp_thread[:interp] + end @ip_name = nil if safe @@ -1221,6 +1294,8 @@ class MultiTkIp @safe_base = true @interp, @ip_name = master.__create_safe_slave_obj(safe_opts, name, tk_opts) + # @interp_thread = nil if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!! + @interp_thread = nil unless WITH_RUBY_VM ### Ruby 1.9 !!!!!!!!!!! if safe safe = master.safe_level if safe < master.safe_level @safe_level = [safe] @@ -1229,6 +1304,8 @@ class MultiTkIp end else @interp, @ip_name = master.__create_trusted_slave_obj(name, tk_opts) + # @interp_thread = nil if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!! + @interp_thread = nil unless WITH_RUBY_VM ### Ruby 1.9 !!!!!!!!!!! if safe safe = master.safe_level if safe < master.safe_level @safe_level = [safe] @@ -1263,11 +1340,11 @@ class MultiTkIp @@DEFAULT_MASTER.assign_receiver_and_watchdog(self) @@IP_TABLE[@threadgroup] = self - _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS) @@TK_TABLE_LIST.size.times{ (tbl = {}).tainted? || tbl.taint @tk_table_list << tbl } + _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS) class << self undef :instance_eval @@ -1345,8 +1422,13 @@ class << MultiTkIp alias __new new private :__new - def new_master(safe=nil, keys={}) + if MultiTkIp::WITH_RUBY_VM + #### TODO !!!!!! + fail RuntimeError, + 'sorry, still not support multiple master-interpreters on Ruby VM' + end + if safe.kind_of?(Hash) keys = safe elsif safe.kind_of?(Integer) @@ -1563,8 +1645,13 @@ class MultiTkIp return if slave? names.each{|name| name = name.to_s + + return if @interp.deleted? @interp._invoke('rename', name, '') + + return if @interp.deleted? @interp._invoke('interp', 'slaves').split.each{|slave| + return if @interp.deleted? @interp._invoke('interp', 'alias', slave, name, '') rescue nil } } @@ -1614,11 +1701,16 @@ class MultiTkIp id = @@TK_TABLE_LIST.size obj = Object.new @@TK_TABLE_LIST << obj - obj.instance_eval <<-EOD + obj.instance_variable_set(:@id, id) + obj.instance_variable_set(:@mutex, Mutex.new) + obj.instance_eval{ + def self.mutex + @mutex + end def self.method_missing(m, *args) - MultiTkIp.tk_object_table(#{id}).__send__(m, *args) + MultiTkIp.tk_object_table(@id).__send__(m, *args) end - EOD + } obj.freeze @@IP_TABLE.each{|tg, ip| ip._add_new_tables } return obj @@ -2338,6 +2430,11 @@ end class MultiTkIp def mainloop(check_root = true, restart_on_dead = true) raise SecurityError, "no permission to manipulate" unless self.manipulable? + + unless WITH_RUBY_VM ### Ruby 1.9 !!!!!!!!!!! + return @interp_thread.value if @interp_thread + end + #return self if self.slave? #return self if self != @@DEFAULT_MASTER if self != @@DEFAULT_MASTER @@ -2746,9 +2843,10 @@ class MultiTkIp i = -1 brace = 1 str.each_byte {|c| + c = c.chr i += 1 - brace += 1 if c == ?{ - brace -= 1 if c == ?} + brace += 1 if c == '{' + brace -= 1 if c == '}' break if brace == 0 } if i == 0 @@ -3187,15 +3285,44 @@ end # encoding convert +class << MultiTkIp + def encoding_table + __getip.encoding_table + end +end class MultiTkIp - def encoding + def encoding_table + @interp.encoding_table + end + + def force_default_encoding=(mode) + raise SecurityError, "no permission to manipulate" unless self.manipulable? + @interp.force_default_encoding = mode + end + def force_default_encoding? raise SecurityError, "no permission to manipulate" unless self.manipulable? - @interp.encoding + @interp.force_default_encoding? end + + def default_encoding=(enc) + raise SecurityError, "no permission to manipulate" unless self.manipulable? + @interp.default_encoding = enc + end + def encoding=(enc) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.encoding = enc end + def encoding_name + raise SecurityError, "no permission to manipulate" unless self.manipulable? + @interp.encoding_name + end + def encoding_obj + raise SecurityError, "no permission to manipulate" unless self.manipulable? + @interp.encoding_obj + end + alias encoding encoding_name + alias default_encoding encoding_name def encoding_convertfrom(str, enc=None) raise SecurityError, "no permission to manipulate" unless self.manipulable? @@ -3213,12 +3340,28 @@ end # remove methods for security class MultiTkIp + INTERP_THREAD = @@DEFAULT_MASTER.instance_variable_get('@interp_thread') + INTERP_MUTEX = INTERP_THREAD[:mutex] + INTERP_ROOT_CHECK = INTERP_THREAD[:root_check] + # undef_method :instance_eval undef_method :instance_variable_get undef_method :instance_variable_set end - +module TkCore + if MultiTkIp::WITH_RUBY_VM && + ! MultiTkIp::RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!! + INTERP_THREAD = MultiTkIp::INTERP_THREAD + INTERP_MUTEX = MultiTkIp::INTERP_MUTEX + INTERP_ROOT_CHECK = MultiTkIp::INTERP_ROOT_CHECK + end +end +class MultiTkIp + remove_const(:INTERP_THREAD) + remove_const(:INTERP_MUTEX) + remove_const(:INTERP_ROOT_CHECK) +end # end of MultiTkIp definition # defend against modification diff --git a/ext/tk/lib/tcltk.rb b/ext/tk/lib/tcltk.rb index 1a6694dbff..7f6f41605d 100644 --- a/ext/tk/lib/tcltk.rb +++ b/ext/tk/lib/tcltk.rb @@ -265,7 +265,7 @@ class TclTkWidget < TclTkCommand # (used in TclTkInterpreter#initialize()) # need two arguments - fail("illegal # of parameter") if args.size != 2 + fail("invalid # of parameter") if args.size != 2 # ip: interpreter(TclTkIp) # exp: tcl/tk representation diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb index 32b5e20bc5..0d00ecf207 100644 --- a/ext/tk/lib/tk.rb +++ b/ext/tk/lib/tk.rb @@ -1,6 +1,5 @@ # # tk.rb - Tk interface module using tcltklib -# $Date$ # by Yukihiro Matsumoto # use Shigehiro's tcltklib @@ -10,6 +9,9 @@ require 'tkutil' # autoload require 'tk/autoload' +# for Mutex +require 'thread' + class TclTkIp # backup original (without encoding) _eval and _invoke alias _eval_without_enc _eval @@ -37,7 +39,12 @@ module TkComm #Tk_CMDTBL = {} #Tk_WINDOWS = {} - Tk_IDs = ["00000".taint, "00000".taint].freeze # [0]-cmdid, [1]-winid + Tk_IDs = ["00000".taint, "00000".taint] # [0]-cmdid, [1]-winid + Tk_IDs.instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } # for backward compatibility Tk_CMDTBL = Object.new @@ -218,7 +225,9 @@ module TkComm TkCore::INTERP.tk_windows[val]? TkCore::INTERP.tk_windows[val] : _genobj_for_tkwidget(val) when /\Ai(_\d+_)?\d+\z/ - TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val + TkImage::Tk_IMGTBL.mutex.synchronize{ + TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val + } when /\A-?\d+\.?\d*(e[-+]?\d+)?\z/ val.to_f when /\\ / @@ -335,6 +344,8 @@ if USE_TCLs_LIST_FUNCTIONS if dst_enc != true && dst_enc != false if (s_enc = s.instance_variable_get(:@encoding)) s_enc = s_enc.to_s + elsif TkCore::WITH_ENCODING + s_enc = s.encoding.name else s_enc = sys_enc end @@ -347,11 +358,20 @@ if USE_TCLs_LIST_FUNCTIONS if sys_enc && dst_enc dst.map!{|s| _toUTF8(s)} ret = TkCore::INTERP._merge_tklist(*dst) - if dst_enc.kind_of?(String) - ret = _fromUTF8(ret, dst_enc) - ret.instance_variable_set(:@encoding, dst_enc) - else - ret.instance_variable_set(:@encoding, 'utf-8') + if TkCore::WITH_ENCODING + if dst_enc.kind_of?(String) + ret = _fromUTF8(ret, dst_enc) + ret.force_encoding(dst_enc) + else + ret.force_encoding('utf-8') + end + else # without encoding + if dst_enc.kind_of?(String) + ret = _fromUTF8(ret, dst_enc) + ret.instance_variable_set(:@encoding, dst_enc) + else + ret.instance_variable_set(:@encoding, 'utf-8') + end end ret else @@ -411,46 +431,6 @@ else tk_split_sublist(token, depth - 1) } end -=begin - def tk_split_list(str) - return [] if str == "" - idx = str.index('{') - while idx and idx > 0 and str[idx-1] == ?\\ - idx = str.index('{', idx+1) - end - unless idx - list = tk_tcl2ruby(str) - unless Array === list - list = [list] - end - return list - end - - list = tk_tcl2ruby(str[0,idx]) - list = [] if list == "" - str = str[idx+1..-1] - i = -1 - escape = false - brace = 1 - str.each_byte {|c| - i += 1 - brace += 1 if c == ?{ && !escape - brace -= 1 if c == ?} && !escape - escape = (c == ?\\) - break if brace == 0 - } - if str.size == i + 1 - return tk_split_list(str[0, i]) - end - if str[0, i] == ' ' - list.push ' ' - else - list.push tk_split_list(str[0, i]) - end - list += tk_split_list(str[i+1..-1]) - list - end -=end def tk_split_simplelist(str, src_enc=true, dst_enc=true) return [] if str == "" @@ -601,7 +581,9 @@ end end def image_obj(val) if val =~ /^i(_\d+_)?\d+$/ - TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val + TkImage::Tk_IMGTBL.mutex.synchronize{ + TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val + } else val end @@ -783,10 +765,12 @@ end id = "c" + TkCore::INTERP._ip_id_ + TkComm::Tk_IDs[0] end def _next_cmd_id - id = _curr_cmd_id - #Tk_IDs[0] += 1 - TkComm::Tk_IDs[0].succ! - id + TkComm::Tk_IDs.mutex.synchronize{ + id = _curr_cmd_id + #Tk_IDs[0] += 1 + TkComm::Tk_IDs[0].succ! + id + } end private :_curr_cmd_id, :_next_cmd_id module_function :_curr_cmd_id, :_next_cmd_id @@ -856,8 +840,10 @@ end return TkCore::INTERP.tk_windows[@path] = self end else - name = "w" + TkCore::INTERP._ip_id_ + Tk_IDs[1] - Tk_IDs[1].succ! + Tk_IDs.mutex.synchronize{ + name = "w" + TkCore::INTERP._ip_id_ + Tk_IDs[1] + Tk_IDs[1].succ! + } end if !ppath or ppath == '.' @path = '.' + name @@ -936,7 +922,12 @@ module TkComm def _bindinfo(what, context=nil) if context - tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]) .collect {|cmdline| + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + enum_obj = tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]).each_line + else + enum_obj = tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]) + end + enum_obj.collect {|cmdline| =begin if cmdline =~ /^rb_out\S* (c(?:_\d+_)?\d+)\s+(.*)$/ #[Tk_CMDTBL[$1], $2] @@ -1082,6 +1073,14 @@ module TkCore include TkComm extend TkComm + WITH_RUBY_VM = Object.const_defined?(:VM) && ::VM.class == Class + WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class + + unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD + ### Ruby 1.9 !!!!!!!!!!!!!!!!!!!!!!!!!! + RUN_EVENTLOOP_ON_MAIN_THREAD = false + end + unless self.const_defined? :INTERP if self.const_defined? :IP_NAME name = IP_NAME.to_s @@ -1099,14 +1098,49 @@ module TkCore opts = '' end - INTERP = TclTkIp.new(name, opts) + if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!! + INTERP = TclTkIp.new(name, opts) + else + INTERP_MUTEX = Mutex.new + INTERP_ROOT_CHECK = ConditionVariable.new + INTERP_THREAD = Thread.new{ + begin + Thread.current[:interp] = interp = TclTkIp.new(name, opts) + rescue => e + Thread.current[:interp] = e + raise e + end + Thread.current[:status] = nil + #sleep + + begin + Thread.current[:status] = TclTkLib.mainloop(true) + rescue Exception=>e + Thread.current[:status] = e + ensure + INTERP_MUTEX.synchronize{ INTERP_ROOT_CHECK.broadcast } + end + Thread.current[:status] = TclTkLib.mainloop(false) + } + + until INTERP_THREAD[:interp] + Thread.pass + end + # INTERP_THREAD.run + raise INTERP_THREAD[:interp] if INTERP_THREAD[:interp].kind_of? Exception + + INTERP = INTERP_THREAD[:interp] + end def INTERP.__getip self end INTERP.instance_eval{ - @tk_cmd_tbl = {}.taint + # @tk_cmd_tbl = {}.taint + @tk_cmd_tbl = Hash.new{|hash, key| + fail IndexError, "unknown command ID '#{key}'" + }.taint def @tk_cmd_tbl.[]=(idx,val) if self.has_key?(idx) && Thread.current.group != ThreadGroup::Default fail SecurityError,"cannot change the entried command" @@ -1157,6 +1191,10 @@ module TkCore class Tk_OBJECT_TABLE def initialize(id) @id = id + @mutex = Mutex.new + end + def mutex + @mutex end def method_missing(m, *args, &b) TkCore::INTERP.tk_object_table(@id).__send__(m, *args, &b) @@ -1342,7 +1380,11 @@ module TkCore "\n---< backtrace of Ruby side >-----\n" + _toUTF8(e.backtrace.join("\n")) + "\n---< backtrace of Tk side >-------" - msg.instance_variable_set(:@encoding, 'utf-8') + if TkCore::WITH_ENCODING + msg.force_encoding('utf-8') + else + msg.instance_variable_set(:@encoding, 'utf-8') + end rescue Exception msg = e.class.inspect + ': ' + e.message + "\n" + "\n---< backtrace of Ruby side >-----\n" + @@ -1397,6 +1439,11 @@ module TkCore bool(tk_call('auto_load', tk_cmd)) end + def after(ms, cmd=Proc.new) + cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret}) + tk_call_without_enc("after",ms,cmdid) # return id + end +=begin def after(ms, cmd=Proc.new) crit_bup = Thread.critical Thread.critical = true @@ -1420,7 +1467,13 @@ module TkCore # tk_call("after",ms,cmdid) # end end +=end + def after_idle(cmd=Proc.new) + cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret}) + tk_call_without_enc('after','idle',cmdid) + end +=begin def after_idle(cmd=Proc.new) crit_bup = Thread.critical Thread.critical = true @@ -1432,6 +1485,7 @@ module TkCore tk_call_without_enc('after','idle',cmdid) end +=end def after_cancel(afterId) tk_call_without_enc('after','cancel',afterId) @@ -1554,7 +1608,27 @@ module TkCore end def mainloop(check_root = true) - TclTkLib.mainloop(check_root) + if !TkCore::WITH_RUBY_VM || TkCore::RUN_EVENTLOOP_ON_MAIN_THREAD + TclTkLib.mainloop(check_root) + else ### Ruby 1.9 !!!!! + begin + TclTkLib.set_eventloop_window_mode(true) + if check_root + INTERP_MUTEX.synchronize{ + INTERP_ROOT_CHECK.wait(INTERP_MUTEX) + status = INTERP_THREAD[:status] + if status + INTERP_THREAD[:status] = nil + raise status if status.kind_of?(Exception) + end + } + else + INTERP_THREAD.value + end + ensure + TclTkLib.set_eventloop_window_mode(false) + end + end end def mainloop_thread? @@ -1562,7 +1636,12 @@ module TkCore # nil : there is no mainloop # false : mainloop is running on the other thread # ( At then, it is dangerous to call Tk interpreter directly. ) - TclTkLib.mainloop_thread? + if !TkCore::WITH_RUBY_VM || TkCore::RUN_EVENTLOOP_ON_MAIN_THREAD + ### Ruby 1.9 !!!!!!!!!!! + TclTkLib.mainloop_thread? + else + Thread.current == INTERP_THREAD + end end def mainloop_exist? @@ -1914,7 +1993,7 @@ module Tk end def root - TkRoot.new + Tk::Root.new end def Tk.load_tclscript(file, enc=nil) @@ -2030,6 +2109,27 @@ module Tk tk_call_without_enc('destroy', '.') end + ################################################ + + def Tk.sleep(ms = nil, id = nil) + if id + var = (id.kind_of?(TkVariable))? id: TkVarAccess.new(id.to_s) + else + var = TkVariable.new + end + + var.value = tk_call_without_enc('after', ms, proc{ var.value = 0 }) if ms + var.thread_wait + ms + end + + def Tk.wakeup(id) + ((id.kind_of?(TkVariable))? id: TkVarAccess.new(id.to_s)).value = 0 + nil + end + + ################################################ + def Tk.pack(*args) TkPack.configure(*args) end @@ -2205,16 +2305,432 @@ end # convert kanji string to/from utf-8 ########################################### if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) + module Tk + module Encoding + extend Encoding + + TkCommandNames = ['encoding'.freeze].freeze + + ############################################# + + if TkCore::WITH_ENCODING ### Ruby 1.9 + RubyEncoding = ::Encoding + + # for saving GC cost + #ENCNAMES_CMD = ['encoding'.freeze, 'names'.freeze] + BINARY_NAME = 'binary'.freeze + UTF8_NAME = 'utf-8'.freeze + DEFAULT_EXTERNAL_NAME = RubyEncoding.default_external.name.freeze + + BINARY = RubyEncoding.find(BINARY_NAME) + UNKNOWN = RubyEncoding.find('ASCII-8BIT') + + ### start of creating ENCODING_TABLE + ENCODING_TABLE = TkCore::INTERP.encoding_table +=begin + ENCODING_TABLE = { + 'binary' => BINARY, + # 'UNKNOWN-8BIT' => UNKNOWN, + } + + list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0], + ENCNAMES_CMD[1]) + TkCore::INTERP._split_tklist(list).each{|name| + begin + enc = RubyEncoding.find(name) + rescue ArgumentError + case name + when 'identity' + enc = BINARY + when 'shiftjis' + enc = RubyEncoding.find('Shift_JIS') + when 'unicode' + enc = RubyEncoding.find('UTF-8') + #if Tk.tk_call('set', 'tcl_platform(byteOrder)') =='littleEndian' + # enc = RubyEncoding.find('UTF-16LE') + #else + # enc = RubyEncoding.find('UTF-16BE') + #end + when 'symbol' + # single byte data + enc = RubyEncoding.find('ASCII-8BIT') ### ??? + else + # unsupported on Ruby, but supported on Tk + enc = TkCore::INTERP.create_dummy_encoding_for_tk(name) + end + end + ENCODING_TABLE[name.freeze] = enc + } +=end +=begin + def ENCODING_TABLE.get_name(enc) + orig_enc = enc + + # unles enc, use system default + # 1st: Ruby/Tk default encoding + # 2nd: Tcl/Tk default encoding + # 3rd: Ruby's default_external + enc ||= TkCore::INTERP.encoding + enc ||= TclTkLib.encoding_system + enc ||= DEFAULT_EXTERNAL_NAME + + if enc.kind_of?(RubyEncoding) + # Ruby's Encoding object + if (name = self.key(enc)) + return name + end + + # Is it new ? + list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0], + ENCNAMES_CMD[1]) + TkComm.simplelist(list).each{|name| + if ((enc == RubyEncoding.find(name)) rescue false) + # new relation!! update table + self[name.freeze] = enc + return name + end + } + else + # String or Symbol ? + if self[name = enc.to_s] + return name + end + + # Is it new ? + if (enc_obj = (RubyEncoding.find(name) rescue false)) + list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0], + ENCNAMES_CMD[1]) + if TkComm.simplelist(list).index(name) + # Tk's encoding name ? + self[name.freeze] = enc_obj # new relation!! update table + return name + else + # Ruby's encoding name ? + if (name = self.key(enc_obj)) + return name + end + end + end + end + + fail ArgumentError, "unsupported Tk encoding '#{orig_enc}'" + end + + def ENCODING_TABLE.get_obj(enc) + # returns the encoding object. + # If 'enc' is the encoding name on Tk only, it returns nil. + ((obj = self[self.get_name(enc)]).kind_of?(RubyEncoding))? obj: nil + end +=end + ### end of creating ENCODING_TABLE + + end + + ############################################# + + if TkCore::WITH_ENCODING + ################################ + ### Ruby 1.9 + ################################ + def force_default_encoding(mode) + TkCore::INTERP.force_default_encoding = mode + end + + def force_default_encoding? + TkCore::INTERP.force_default_encoding? + end + + def default_encoding=(enc) + TkCore::INTERP.default_encoding = Tk::Encoding::ENCODING_TABLE.get_name(enc) + end + + def encoding=(enc) + TkCore::INTERP.encoding = Tk::Encoding::ENCODING_TABLE.get_name(enc) + end + + def encoding_name + Tk::Encoding::ENCODING_TABLE.get_name(TkCore::INTERP.encoding) + end + def encoding_obj + Tk::Encoding::ENCODING_TABLE.get_obj(TkCore::INTERP.encoding) + end + alias encoding encoding_name + alias default_encoding encoding_name + + def tk_encoding_names + TkComm.simplelist(TkCore::INTERP._invoke_without_enc(Tk::Encoding::ENCNAMES_CMD[0], Tk::Encoding::ENCNAMES_CMD[1])) + end + def encoding_names + self.tk_encoding_names.find_all{|name| + Tk::Encoding::ENCODING_TABLE.get_name(name) rescue false + } + end + def encoding_objs + self.tk_encoding_names.map!{|name| + Tk::Encoding::ENCODING_TABLE.get_obj(name) rescue nil + }.compact + end + + def encoding_system=(enc) + TclTkLib.encoding_system = Tk::Encoding::ENCODING_TABLE.get_name(enc) + end + + def encoding_system_name + Tk::Encoding::ENCODING_TABLE.get_name(TclTkLib.encoding_system) + end + def encoding_system_obj + Tk::Encoding::ENCODING_TABLE.get_obj(TclTkLib.encoding_system) + end + alias encoding_system encoding_system_name + + ################################ + else + ################################ + ### Ruby 1.8- + ################################ + def force_default_encoding=(mode) + true + end + + def force_default_encoding? + true + end + + def default_encoding=(enc) + TkCore::INTERP.default_encoding = enc + end + + def encoding=(enc) + TkCore::INTERP.encoding = enc + end + + def encoding_obj + TkCore::INTERP.encoding + end + def encoding_name + TkCore::INTERP.encoding + end + alias encoding encoding_name + alias default_encoding encoding_name + + def tk_encoding_names + TkComm.simplelist(Tk.tk_call('encoding', 'names')) + end + def encoding_objs + self.tk_encoding_names + end + def encoding_names + self.tk_encoding_names + end + + def encoding_system=(enc) + TclTkLib.encoding_system = enc + end + + def encoding_system_name + TclTkLib.encoding_system + end + def encoding_system_obj + TclTkLib.encoding_system + end + alias encoding_system encoding_system_name + + ################################ + end + + def encoding_convertfrom(str, enc=nil) + enc = encoding_system_name unless enc + str = str.dup + if TkCore::WITH_ENCODING + if str.kind_of?(Tk::EncodedString) + str.__instance_variable_set('@encoding', nil) + else + str.instance_variable_set('@encoding', nil) + end + str.force_encoding('binary') + else + str.instance_variable_set('@encoding', 'binary') + end + ret = TkCore::INTERP._invoke_without_enc('encoding', 'convertfrom', + enc, str) + if TkCore::WITH_ENCODING + ret.force_encoding('utf-8') + else + Tk::UTF8_String.new(ret) + end + ret + end + alias encoding_convert_from encoding_convertfrom + + def encoding_convertto(str, enc=nil) + # str must be a UTF-8 string + enc = encoding_system_name unless enc + ret = TkCore::INTERP._invoke_without_enc('encoding', 'convertto', + enc, str) + #ret.instance_variable_set('@encoding', 'binary') + if TkCore::WITH_ENCODING + #ret.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj('binary')) + ret.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj(enc)) + end + ret + end + alias encoding_convert_to encoding_convertto + + def encoding_dirs + # Tcl8.5 feature + TkComm.simplelist(Tk.tk_call_without_enc('encoding', 'dirs')) + end + + def encoding_dirs=(dir_list) # an array or a Tcl's list string + # Tcl8.5 feature + Tk.tk_call_without_enc('encoding', 'dirs', dir_list) + end + end + + extend Encoding + end + class TclTkIp + def force_default_encoding=(mode) + @force_default_encoding = (mode)? true: false + end + + def force_default_encoding? + @force_default_encoding ||= false + end + + def default_encoding=(name) + name = name.name if name.kind_of?(::Encoding) if Tk::WITH_ENCODING + @encoding = name + end + # from tkencoding.rb by ttate@jaist.ac.jp - attr_accessor :encoding + #attr_accessor :encoding + def encoding=(name) + self.force_default_encoding = true # for comaptibility + self.default_encoding = name + end - alias __eval _eval - alias __invoke _invoke + def encoding_name + (@encoding)? @encoding.dup: nil + end + alias encoding encoding_name + alias default_encoding encoding_name + + def encoding_obj + if Tk::WITH_ENCODING + Tk::Encoding.tcl2rb_encoding(@encoding) + else + (@encoding)? @encoding.dup: nil + end + end alias __toUTF8 _toUTF8 alias __fromUTF8 _fromUTF8 + if Object.const_defined?(:Encoding) && ::Encoding.class == Class + # with Encoding (Ruby 1.9+) + # + # use functions on Tcl as default. + # but when unsupported encoding on Tcl, use methods on Ruby. + # + def _toUTF8(str, enc = nil) + if enc + # use given encoding + begin + enc_name = Tk::Encoding::ENCODING_TABLE.get_name(enc) + rescue + # unknown encoding for Tk -> try to convert encoding on Ruby + str = str.dup.force_encoding(enc) + str.encode!(Tk::Encoding::UTF8_NAME) # modify self !! + return str # if no error, probably succeed converting + end + end + + enc_name ||= str.instance_variable_get(:@encoding) + + enc_name ||= + Tk::Encoding::ENCODING_TABLE.get_name(str.encoding) rescue nil + + unless enc_name + # str.encoding isn't supported by Tk -> try to convert on Ruby + begin + return str.encode(Tk::Encoding::UTF8_NAME) # new string + rescue + # error -> ignore, try to use default encoding of Ruby/Tk + end + end + + #enc_name ||= + # Tk::Encoding::ENCODING_TABLE.get_name(Tk.encoding) rescue nil + enc_name ||= Tk::Encoding::ENCODING_TABLE.get_name(nil) + + # is 'binary' encoding? + if enc_name == Tk::Encoding::BINARY_NAME + return str.dup.force_encoding(Tk::Encoding::BINARY_NAME) + end + + # force default encoding? + if ! str.kind_of?(Tk::EncodedString) && self.force_default_encoding? + enc_name = Tk::Encoding::ENCODING_TABLE.get_name(Tk.default_encoding) + end + + encstr = __toUTF8(str, enc_name) + encstr.force_encoding(Tk::Encoding::UTF8_NAME) + encstr + end + def _fromUTF8(str, enc = nil) + # str must be UTF-8 or binary. + enc_name = str.instance_variable_get(:@encoding) + enc_name ||= + Tk::Encoding::ENCODING_TABLE.get_name(str.encoding) rescue nil + + # is 'binary' encoding? + if enc_name == Tk::Encoding::BINARY_NAME + return str.dup.force_encoding(Tk::Encoding::BINARY_NAME) + end + + # get target encoding name (if enc == nil, use default encoding) + begin + enc_name = Tk::Encoding::ENCODING_TABLE.get_name(enc) + rescue + # then, enc != nil + # unknown encoding for Tk -> try to convert encoding on Ruby + str = str.dup.force_encoding(Tk::Encoding::UTF8_NAME) + str.encode!(enc) # modify self !! + return str # if no error, probably succeed converting + end + + encstr = __fromUTF8(str, enc_name) + encstr.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj(enc_name)) + encstr + end + ### + else + # without Encoding (Ruby 1.8) + def _toUTF8(str, encoding = nil) + __toUTF8(str, encoding) + end + def _fromUTF8(str, encoding = nil) + __fromUTF8(str, encoding) + end + ### + end + + alias __eval _eval + alias __invoke _invoke + + def _eval(cmd) + _fromUTF8(__eval(_toUTF8(cmd))) + end + + def _invoke(*cmds) + _fromUTF8(__invoke(*(cmds.collect{|cmd| _toUTF8(cmd)}))) + end + + alias _eval_with_enc _eval + alias _invoke_with_enc _invoke + =begin #### --> definition is moved to TclTkIp module @@ -2264,17 +2780,6 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) end =end - def _eval(cmd) - _fromUTF8(__eval(_toUTF8(cmd))) - end - - def _invoke(*cmds) - _fromUTF8(__invoke(*(cmds.collect{|cmd| _toUTF8(cmd)}))) - end - - alias _eval_with_enc _eval - alias _invoke_with_enc _invoke - =begin def _eval(cmd) if defined?(@encoding) && @encoding != 'utf-8' @@ -2331,127 +2836,214 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) module TclTkLib class << self - alias _encoding encoding - alias _encoding= encoding= - def encoding=(name) - TkCore::INTERP.encoding = name - end - def encoding - TkCore::INTERP.encoding + def force_default_encoding=(mode) + TkCore::INTERP.force_default_encoding = mode end - end - end - module Tk - module Encoding - extend Encoding + def force_default_encoding? + TkCore::INTERP.force_default_encoding? + end - TkCommandNames = ['encoding'.freeze].freeze + def default_encoding=(name) + TkCore::INTERP.default_encoding = name + end + alias _encoding encoding + alias _encoding= encoding= def encoding=(name) + name = name.name if name.kind_of?(::Encoding) if Tk::WITH_ENCODING TkCore::INTERP.encoding = name end - def encoding + def encoding_name TkCore::INTERP.encoding end + alias encoding encoding_name + alias default_encoding encoding_name - def encoding_names - TkComm.simplelist(Tk.tk_call('encoding', 'names')) + def encoding_obj + if Tk::WITH_ENCODING + Tk::Encoding.tcl2rb_encoding(TkCore::INTERP.encoding) + else + TkCore::INTERP.encoding + end end + end + end - def encoding_system - Tk.tk_call('encoding', 'system') + # estimate encoding + unless TkCore::WITH_ENCODING + case $KCODE + when /^e/i # EUC + Tk.encoding = 'euc-jp' + Tk.encoding_system = 'euc-jp' + when /^s/i # SJIS + begin + if Tk.encoding_system == 'cp932' + Tk.encoding = 'cp932' + else + Tk.encoding = 'shiftjis' + Tk.encoding_system = 'shiftjis' + end + rescue StandardError, NameError + Tk.encoding = 'shiftjis' + Tk.encoding_system = 'shiftjis' end - - def encoding_system=(enc) - Tk.tk_call('encoding', 'system', enc) + when /^u/i # UTF8 + Tk.encoding = 'utf-8' + Tk.encoding_system = 'utf-8' + else # NONE + if defined? DEFAULT_TK_ENCODING + Tk.encoding_system = DEFAULT_TK_ENCODING end - - def encoding_convertfrom(str, enc=nil) - # str is an usual enc string or a Tcl's internal string expression - # in enc (which is returned from 'encoding_convertto' method). - # the return value is a UTF-8 string. - enc = encoding_system unless enc - ret = TkCore::INTERP.__invoke('encoding', 'convertfrom', enc, str) - ret.instance_variable_set('@encoding', 'utf-8') - ret + begin + Tk.encoding = Tk.encoding_system + rescue StandardError, NameError + Tk.encoding = 'utf-8' + Tk.encoding_system = 'utf-8' end - alias encoding_convert_from encoding_convertfrom + end - def encoding_convertto(str, enc=nil) - # str must be a UTF-8 string. - # The return value is a Tcl's internal string expression in enc. - # To get an usual enc string, use Tk.fromUTF8(ret_val, enc). - enc = encoding_system unless enc - ret = TkCore::INTERP.__invoke('encoding', 'convertto', enc, str) - ret.instance_variable_set('@encoding', 'binary') - ret - end - alias encoding_convert_to encoding_convertto + else ### Ruby 1.9 !!!!!!!!!!!! + loc_enc_obj = ::Encoding.find(::Encoding.locale_charmap) + ext_enc_obj = ::Encoding.default_external + tksys_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(Tk.encoding_system) + # p [Tk.encoding, Tk.encoding_system, loc_enc_obj, ext_enc_obj] - def encoding_dirs - # Tcl8.5 feature - TkComm.simplelist(Tk.tk_call_without_enc('encoding', 'dirs')) +=begin + if ext_enc_obj == Tk::Encoding::UNKNOWN + if defind? DEFAULT_TK_ENCODING + if DEFAULT_TK_ENCODING.kind_of?(::Encoding) + tk_enc_name = DEFAULT_TK_ENCODING.name + tksys_enc_name = DEFAULT_TK_ENCODING.name + else + tk_enc_name = DEFAULT_TK_ENCODING + tksys_enc_name = DEFAULT_TK_ENCODING + end + else + tk_enc_name = loc_enc_obj.name + tksys_enc_name = loc_enc_obj.name end + else + tk_enc_name = ext_enc_obj.name + tksys_enc_name = ext_enc_obj.name + end - def encoding_dirs=(dir_list) # an array or a Tcl's list string - # Tcl8.5 feature - Tk.tk_call_without_enc('encoding', 'dirs', dir_list) + # Tk.encoding = tk_enc_name + Tk.default_encoding = tk_enc_name + Tk.encoding_system = tksys_enc_name +=end + + if ext_enc_obj == Tk::Encoding::UNKNOWN + if loc_enc_obj == Tk::Encoding::UNKNOWN + # use Tk.encoding_system + else + # use locale_charmap + begin + loc_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(loc_enc_obj) + if loc_enc_name && loc_enc_name != tksys_enc_name + # use locale_charmap + Tk.encoding_system = loc_enc_name + else + # use Tk.encoding_system + end + rescue ArgumentError + # unsupported encoding on Tk -> use Tk.encoding_system + end + end + else + begin + ext_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(ext_enc_obj) + if ext_enc_name && ext_enc_name != tksys_enc_name + # use default_external + Tk.encoding_system = ext_enc_name + else + # use Tk.encoding_system + end + rescue ArgumentError + # unsupported encoding on Tk -> use Tk.encoding_system end end - extend Encoding - end + # setup Tk.encoding + enc_name = nil - # estimate encoding - case $KCODE - when /^e/i # EUC - Tk.encoding = 'euc-jp' - Tk.encoding_system = 'euc-jp' - when /^s/i # SJIS begin - if Tk.encoding_system == 'cp932' - Tk.encoding = 'cp932' - else - Tk.encoding = 'shiftjis' - Tk.encoding_system = 'shiftjis' + default_def = DEFAULT_TK_ENCODING + if ::Encoding.find(default_def.to_s) != Tk::Encoding::UNKNOWN + enc_name = Tk::Encoding::ENCODING_TABLE.get_name(default_def) end - rescue StandardError, NameError - Tk.encoding = 'shiftjis' - Tk.encoding_system = 'shiftjis' - end - when /^u/i # UTF8 - Tk.encoding = 'utf-8' - Tk.encoding_system = 'utf-8' - else # NONE - if defined? DEFAULT_TK_ENCODING - Tk.encoding_system = DEFAULT_TK_ENCODING + rescue NameError + # ignore + enc_name = nil + rescue ArgumentError + enc_name = nil + fail ArgumentError, + "DEFAULT_TK_ENCODING has an unknown encoding #{default_def}" end - begin - Tk.encoding = Tk.encoding_system - rescue StandardError, NameError - Tk.encoding = 'utf-8' - Tk.encoding_system = 'utf-8' + + unless enc_name + if ext_enc_obj == Tk::Encoding::UNKNOWN + if loc_enc_obj == Tk::Encoding::UNKNOWN + # use Tk.encoding_system + enc_name = tksys_enc_name + else + # use locale_charmap + begin + loc_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(loc_enc_obj) + if loc_enc_name && loc_enc_name != tksys_enc_name + # use locale_charmap + enc_name = loc_enc_name + else + # use Tk.encoding_system + enc_name = tksys_enc_name + end + rescue ArgumentError + # unsupported encoding on Tk -> use Tk.encoding_system + enc_name = tksys_enc_name + end + end + else + begin + ext_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(ext_enc_obj) + if ext_enc_name && ext_enc_name != tksys_enc_name + # use default_external + enc_name = ext_enc_name + else + # use Tk.encoding_system + enc_name = tksys_enc_name + end + rescue ArgumentError + # unsupported encoding on Tk -> use Tk.encoding_system + enc_name = tksys_enc_name + end + end end + + Tk.default_encoding = (enc_name)? enc_name: tksys_enc_name end else # dummy methods - class TclTkIp - attr_accessor :encoding - - alias __eval _eval - alias __invoke _invoke - - alias _eval_with_enc _eval - alias _invoke_with_enc _invoke - end - module Tk module Encoding extend Encoding + def force_default_encoding=(mode) + nil + end + + def force_default_encoding? + nil + end + + def default_encoding=(enc) + nil + end + def default_encoding + nil + end + def encoding=(name) nil end @@ -2487,6 +3079,16 @@ else extend Encoding end + + class TclTkIp + attr_accessor :encoding + + alias __eval _eval + alias __invoke _invoke + + alias _eval_with_enc _eval + alias _invoke_with_enc _invoke + end end @@ -2816,6 +3418,14 @@ module TkConfigMethod include TkUtil include TkTreatFont + def TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + @mode || false + end + def TkConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) + fail SecurityError, "can't change the mode" if $SAFE>=4 + @mode = (mode)? true: false + end + def __cget_cmd [self.path, 'cget'] end @@ -2943,7 +3553,7 @@ module TkConfigMethod val end - def cget(slot) + def __cget_core(slot) orig_slot = slot slot = slot.to_s @@ -3019,8 +3629,17 @@ module TkConfigMethod tk_tcl2ruby(tk_call_without_enc(*(__cget_cmd << "-#{slot}")), true) end end + private :__cget_core - def configure(slot, value=None) + def cget(slot) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + __cget_core(slot) + else + __cget_core(slot) rescue nil + end + end + + def __configure_core(slot, value=None) if slot.kind_of? Hash slot = _symbolkey2str(slot) @@ -3083,12 +3702,45 @@ module TkConfigMethod end self end + private :__configure_core + + def __check_available_configure_options(keys) + availables = self.current_configinfo.keys + + # add non-standard keys + availables |= __font_optkeys.map{|k| + [k.to_s, "latin#{k}", "ascii#{k}", "kanji#{k}"] + }.flatten + availables |= __methodcall_optkeys.keys.map{|k| k.to_s} + availables |= __keyonly_optkeys.keys.map{|k| k.to_s} + + keys = _symbolkey2str(keys) + keys.delete_if{|k, v| !(availables.include?(k))} + end + + def configure(slot, value=None) + unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + __configure_core(slot, value) + else + if slot.kind_of?(Hash) + begin + __configure_core(slot) + rescue + slot = __check_available_configure_options(slot) + __configure_core(slot) unless slot.empty? + end + else + __configure_core(slot, value) rescue nil + end + end + self + end def configure_cmd(slot, value) configure(slot, install_cmd(value)) end - def configinfo(slot = nil) + def __configinfo_core(slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/) @@ -3099,6 +3751,10 @@ module TkConfigMethod conf[__configinfo_struct[:key]][1..-1] if ( ! __configinfo_struct[:alias] \ || conf.size > __configinfo_struct[:alias] + 1 ) + fnt = conf[__configinfo_struct[:default_value]] + if TkFont.is_system_font?(fnt) + conf[__configinfo_struct[:default_value]] = TkNamedFont.new(fnt) + end conf[__configinfo_struct[:current_value]] = fontobj(fontkey) elsif ( __configinfo_struct[:alias] \ && conf.size == __configinfo_struct[:alias] + 1 \ @@ -3435,6 +4091,11 @@ module TkConfigMethod fontconf = ret.assoc(optkey) if fontconf && fontconf.size > 2 ret.delete_if{|inf| inf[0] =~ /^(|latin|ascii|kanji)#{optkey}$/} + fnt = fontconf[__configinfo_struct[:default_value]] + if TkFont.is_system_font?(fnt) + fontconf[__configinfo_struct[:default_value]] \ + = TkNamedFont.new(fnt) + end fontconf[__configinfo_struct[:current_value]] = fontobj(optkey) ret.push(fontconf) end @@ -3459,6 +4120,10 @@ module TkConfigMethod if ( ! __configinfo_struct[:alias] \ || conf.size > __configinfo_struct[:alias] + 1 ) + fnt = conf[__configinfo_struct[:default_value]] + if TkFont.is_system_font?(fnt) + conf[__configinfo_struct[:default_value]] = TkNamedFont.new(fnt) + end conf[__configinfo_struct[:current_value]] = fontobj(fontkey) { conf.shift => conf } elsif ( __configinfo_struct[:alias] \ @@ -3806,6 +4471,11 @@ module TkConfigMethod ret.delete('latin' << optkey) ret.delete('ascii' << optkey) ret.delete('kanji' << optkey) + fnt = fontconf[__configinfo_struct[:default_value]] + if TkFont.is_system_font?(fnt) + fontconf[__configinfo_struct[:default_value]] \ + = TkNamedFont.new(fnt) + end fontconf[__configinfo_struct[:current_value]] = fontobj(optkey) ret[optkey] = fontconf end @@ -3820,6 +4490,19 @@ module TkConfigMethod end end end + private :__configinfo_core + + def configinfo(slot = nil) + if slot && TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ + begin + __configinfo_core(slot) + rescue + Array.new(__configinfo_struct.values.max).unshift(slot.to_s) + end + else + __configinfo_core(slot) + end + end def current_configinfo(slot = nil) if TkComm::GET_CONFIGINFO_AS_ARRAY @@ -3919,7 +4602,12 @@ class TkObject If TkCommandNames[0] is a string (not a null string), @@ -4069,13 +4766,35 @@ class TkWindow' + end + end + def exist? TkWinfo.exist?(self) end @@ -4585,7 +5304,7 @@ class TkWindow 'tk/button', - autoload :ValidateConfigure, 'tk/validation' - autoload :ItemValidateConfigure, 'tk/validation' + :TkCanvas => 'tk/canvas', - autoload :EncodedString, 'tk/encodedstr' - def Tk.EncodedString(str, enc = nil); Tk::EncodedString.new(str, enc); end + :TkCheckButton => 'tk/checkbutton', + :TkCheckbutton => 'tk/checkbutton', - autoload :BinaryString, 'tk/encodedstr' - def Tk.BinaryString(str); Tk::BinaryString.new(str); end + # :TkDialog => 'tk/dialog', + # :TkDialog2 => 'tk/dialog', + # :TkDialogObj => 'tk/dialog', + # :TkWarning => 'tk/dialog', + # :TkWarning2 => 'tk/dialog', + # :TkWarningObj => 'tk/dialog', - autoload :UTF8_String, 'tk/encodedstr' - def Tk.UTF8_String(str); Tk::UTF8_String.new(str); end + :TkEntry => 'tk/entry', + + :TkFrame => 'tk/frame', + + :TkLabel => 'tk/label', + + :TkLabelFrame => 'tk/labelframe', + :TkLabelframe => 'tk/labelframe', + + :TkListbox => 'tk/listbox', + + :TkMacResource => 'tk/macpkg', + + :TkMenu => 'tk/menu', + :TkMenuClone => 'tk/menu', + :TkCloneMenu => 'tk/menu', + # :TkSystemMenu => 'tk/menu', + :TkSysMenu_Help => 'tk/menu', + :TkSysMenu_System => 'tk/menu', + :TkSysMenu_Apple => 'tk/menu', + :TkMenubutton => 'tk/menu', + :TkMenuButton => 'tk/menu', + :TkOptionMenubutton => 'tk/menu', + :TkOptionMenuButton => 'tk/menu', + + :TkMessage => 'tk/message', + + :TkPanedWindow => 'tk/panedwindow', + :TkPanedwindow => 'tk/panedwindow', + + :TkRadioButton => 'tk/radiobutton', + :TkRadiobutton => 'tk/radiobutton', + + # :TkRoot => 'tk/root', + + :TkScale => 'tk/scale', + + :TkScrollbar => 'tk/scrollbar', + :TkXScrollbar => 'tk/scrollbar', + :TkYScrollbar => 'tk/scrollbar', + + :TkSpinbox => 'tk/spinbox', + + :TkText => 'tk/text', + + :TkToplevel => 'tk/toplevel', + + :TkWinDDE => 'tk/winpkg', + :TkWinRegistry => 'tk/winpkg', + } + + @TOPLEVEL_ALIAS_OWNER = {} + + @TOPLEVEL_ALIAS_SETUP_PROC = {} + + @current_default_widget_set = nil +end + + +############################################ +# methods to control default widget set +############################################ + +class << Tk + def default_widget_set + @current_default_widget_set + end + + def default_widget_set=(target) + target = target.to_sym + return target if target == @current_default_widget_set + + if (cmd = @TOPLEVEL_ALIAS_SETUP_PROC[target]) + cmd.call(target) + end + + _replace_toplevel_aliases(target) + end + + def __set_toplevel_aliases__(target, obj, *symbols) + @TOPLEVEL_ALIAS_TABLE[target = target.to_sym] ||= {} + symbols.each{|sym| + @TOPLEVEL_ALIAS_TABLE[target][sym = sym.to_sym] = obj + # if @current_default_widget_set == target + if @TOPLEVEL_ALIAS_OWNER[sym] == target + Object.class_eval{remove_const sym} if Object.const_defined?(sym) + Object.const_set(sym, obj) + end + } + end + + ################################### + private + def _replace_toplevel_aliases(target) + # check already autoloaded + if (table = @TOPLEVEL_ALIAS_TABLE[current = @current_default_widget_set]) + table.each{|sym, file| + if !Object.autoload?(sym) && Object.const_defined?(sym) && + @TOPLEVEL_ALIAS_TABLE[current][sym].kind_of?(String) + # autoload -> class + @TOPLEVEL_ALIAS_TABLE[current][sym] = Object.const_get(sym) + end + } + end + + # setup autoloads + @TOPLEVEL_ALIAS_TABLE[target].each{|sym, file| + Object.class_eval{remove_const sym} if Object.const_defined?(sym) + if file.kind_of?(String) + # file => autoload target file + Object.autoload(sym, file) + else + # file => loaded class object + Object.const_set(sym, file) + end + @TOPLEVEL_ALIAS_OWNER[sym] = target + } + + # update current alias + @current_default_widget_set = target + end +end + +############################################ +# setup default widget set => :Tk +Tk.default_widget_set = :Tk + + +############################################ +# depend on the version of Tcl/Tk +# 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) + # Tcl/Tk 8.5 beta or later + Object.autoload :Ttk, 'tkextlib/tile' + Tk.autoload :Tile, 'tkextlib/tile' + + 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 # require 'tk' @@ -40,7 +39,7 @@ module TkCanvasItemConfig private :__item_pathname end -class TkCanvas use my classname base_class_name = self.class.name if base_class_name == '' @@ -69,7 +71,8 @@ module TkComposite else # no valid WidgetClassName - if self.class < TkFrame || self.class.superclass < TkComposite + #if self.class < TkFrame || self.class.superclass < TkComposite + if self.class < TkFrame || self.class.superclass < Tk::Frame || self.class.superclass < TkComposite # my class name is valid for the base frame -> use my classname base_class_name = self.class.name if base_class_name == '' @@ -108,8 +111,12 @@ module TkComposite end if base_class_name + # @frame = Tk::Frame.new(parent, :class=>base_class_name) + # --> use current TkFrame class @frame = TkFrame.new(parent, :class=>base_class_name) else + # @frame = Tk::Frame.new(parent) + # --> use current TkFrame class @frame = TkFrame.new(parent) end @path = @epath = @frame.path @@ -133,6 +140,11 @@ module TkComposite def initialize_composite(*args) end private :initialize_composite + def inspect + str = super + str.chop << ' @epath=' << @epath.inspect << '>' + end + def option_methods(*opts) opts.each{|m_set, m_cget, m_info| m_set = m_set.to_s 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/entry.rb b/ext/tk/lib/tk/entry.rb index 4ac3f28229..8ce8def1e7 100644 --- a/ext/tk/lib/tk/entry.rb +++ b/ext/tk/lib/tk/entry.rb @@ -1,6 +1,5 @@ # # tk/entry.rb - Tk entry classes -# $Date$ # by Yukihiro Matsumoto require 'tk' @@ -8,7 +7,7 @@ require 'tk/label' require 'tk/scrollable' require 'tk/validation' -class TkEntry (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, @@ -223,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 } @@ -298,31 +301,54 @@ module TkEvent [ ?b, ?n, :num ], [ ?c, ?n, :count ], [ ?d, ?s, :detail ], + # ?e [ ?f, ?b, :focus ], + # ?g [ ?h, ?n, :height ], [ ?i, ?s, :win_hex ], + # ?j [ ?k, ?n, :keycode ], + # ?l [ ?m, ?s, :mode ], + # ?n [ ?o, ?b, :override ], [ ?p, ?s, :place ], + # ?q + # ?r [ ?s, ?x, :state ], [ ?t, ?n, :time ], + # ?u + [ ?v, ?n, :value_mask ], [ ?w, ?n, :width ], [ ?x, ?n, :x ], [ ?y, ?n, :y ], + # ?z [ ?A, ?s, :char ], [ ?B, ?n, :borderwidth ], + # ?C [ ?D, ?n, :wheel_delta ], [ ?E, ?b, :send_event ], + # ?F + # ?G + # ?H + # ?I + # ?J [ ?K, ?s, :keysym ], + # ?L + # ?M [ ?N, ?n, :keysym_num ], + # ?O [ ?P, ?s, :property ], + # ?Q [ ?R, ?s, :rootwin_id ], [ ?S, ?s, :subwindow ], [ ?T, ?n, :type ], + # ?U + # ?V [ ?W, ?w, :widget ], [ ?X, ?n, :x_root ], [ ?Y, ?n, :y_root ], + # ?Z nil ] @@ -345,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 ab58ac5762..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,24 +1057,32 @@ 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(';') winobj = tk_tcl2ruby(win) - if winobj.kind_of? TkText + #if winobj.kind_of? TkText + if winobj.kind_of?(TkText) || winobj.kind_of?(Tk::Text) if optkey ret.push([winobj, winobj.tagid2obj(tag), optkey]) else ret.push([winobj, winobj.tagid2obj(tag)]) end - elsif winobj.kind_of? TkCanvas + #elsif winobj.kind_of? TkCanvas + elsif winobj.kind_of?(TkCanvas) || winobj.kind_of?(Tk::Canvas) if (tagobj = TkcTag.id2obj(winobj, tag)).kind_of? TkcTag if optkey ret.push([winobj, tagobj, optkey]) @@ -925,7 +1102,8 @@ class TkFont ret.push([winobj, tag]) end end - elsif winobj.kind_of? TkMenu + #elsif winobj.kind_of? TkMenu + elsif winobj.kind_of?(TkMenu) || winobj.kind_of?(Tk::Menu) if optkey ret.push([winobj, tag, optkey]) else @@ -957,6 +1135,8 @@ class TkFont @compoundfont end alias font_id font + alias name font + alias to_s font def latin_font_id @latinfont @@ -964,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 @@ -978,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 @@ -1065,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 @@ -1080,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 @@ -1096,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 @@ -1119,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 @@ -1166,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 @@ -1471,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?(';') @@ -1504,11 +1942,14 @@ module TkFont::CoreMethods optkey = 'font' if optkey == nil || optkey == '' winobj = tk_tcl2ruby(win) # winobj.tagfont_configure(tag, {'font'=>@latinfont}) - if winobj.kind_of? TkText + #if winobj.kind_of? TkText + if winobj.kind_of?(TkText) || winobj.kind_of?(Tk::Text) tk_call(win, 'tag', 'configure', tag, "-#{optkey}", @latinfont) - elsif winobj.kind_of? TkCanvas + #elsif winobj.kind_of? TkCanvas + elsif winobj.kind_of?(TkCanvas) || winobj.kind_of?(Tk::Canvas) tk_call(win, 'itemconfigure', tag, "-#{optkey}", @latinfont) - elsif winobj.kind_of? TkMenu + #elsif winobj.kind_of? TkMenu + elsif winobj.kind_of?(TkMenu) || winobj.kind_of?(Tk::Menu) tk_call(win, 'entryconfigure', tag, "-#{optkey}", @latinfont) else raise RuntimeError, "unknown widget type" @@ -1518,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 } @@ -1531,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?(';') @@ -1539,11 +1986,14 @@ module TkFont::CoreMethods optkey = 'kanjifont' unless optkey winobj = tk_tcl2ruby(win) # winobj.tagfont_configure(tag, {'kanjifont'=>@kanjifont}) - if winobj.kind_of? TkText + #if winobj.kind_of? TkText + if winobj.kind_of?(TkText) || winobj.kind_of?(Tk::Text) tk_call(win, 'tag', 'configure', tag, "-#{optkey}", @kanjifont) - elsif winobj.kind_of? TkCanvas + #elsif winobj.kind_of? TkCanvas + elsif winobj.kind_of?(TkCanvas) || winobj.kind_of?(Tk::Canvas) tk_call(win, 'itemconfigure', tag, "-#{optkey}", @kanjifont) - elsif winobj.kind_of? TkMenu + #elsif winobj.kind_of? TkMenu + elsif winobj.kind_of?(TkMenu) || winobj.kind_of?(Tk::Menu) tk_call(win, 'entryconfigure', tag, "-#{optkey}", @latinfont) else raise RuntimeError, "unknown widget type" @@ -1553,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 } @@ -1618,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 @@ -1711,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 @@ -1720,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 @@ -1760,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/frame.rb b/ext/tk/lib/tk/frame.rb index 6636fef5b5..263b160f29 100644 --- a/ext/tk/lib/tk/frame.rb +++ b/ext/tk/lib/tk/frame.rb @@ -3,7 +3,7 @@ # require 'tk' -class TkFrame=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/label.rb b/ext/tk/lib/tk/label.rb index 8b45db9b30..80b3d778f1 100644 --- a/ext/tk/lib/tk/label.rb +++ b/ext/tk/lib/tk/label.rb @@ -3,7 +3,7 @@ # require 'tk' -class TkLabelmenu_name, :tearoff=>tearoff) + # --> use current TkMenu class menu = TkMenu.new(parent, :widgetname=>menu_name, :tearoff=>tearoff) else + #menu = Tk::Menu.new(parent, :tearoff=>tearoff) + # --> use current TkMenu class menu = TkMenu.new(parent, :tearoff=>tearoff) end @@ -150,7 +154,7 @@ module TkMenuSpec def _use_menubar?(parent) use_menubar = false - if parent.kind_of?(TkRoot) || parent.kind_of?(TkToplevel) + if parent.kind_of?(Tk::Root) || parent.kind_of?(Tk::Toplevel) return true else begin @@ -164,7 +168,11 @@ module TkMenuSpec private :_use_menubar? def _create_menu_for_menubar(parent) - unless (mbar = parent.menu).kind_of?(TkMenu) + #unless (mbar = parent.menu).kind_of?(TkMenu) + # --> use current TkMenu class + mbar = parent.menu + unless parent.menu.kind_of?(Tk::Menu) || parent.menu.kind_of?(TkMenu) + #mbar = Tk::Menu.new(parent, :tearoff=>false) mbar = TkMenu.new(parent, :tearoff=>false) parent.menu(mbar) end @@ -221,6 +229,8 @@ module TkMenuSpec else # menubar by menubuttons + #mbtn = Tk::Menubutton.new(parent) + # --> use current TkMenubutton class mbtn = TkMenubutton.new(parent) menu_name = nil diff --git a/ext/tk/lib/tk/message.rb b/ext/tk/lib/tk/message.rb index 79121bebb3..946b68c704 100644 --- a/ext/tk/lib/tk/message.rb +++ b/ext/tk/lib/tk/message.rb @@ -4,7 +4,7 @@ require 'tk' require 'tk/label' -class TkMessage-----\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 # 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 a806f3971d..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) } @@ -362,7 +368,7 @@ module TkOptionDB def new_proc_class_random(klass, func, safe = 4, add = false, &b) eval_under_random_base(){ - TkOption.new_proc_class(klass, func, safe, add, self, &b) + TkOptionDB.new_proc_class(klass, func, safe, add, self, &b) } end module_function :new_proc_class_random diff --git a/ext/tk/lib/tk/package.rb b/ext/tk/lib/tk/package.rb index d1eb27674d..0c329732f5 100644 --- a/ext/tk/lib/tk/package.rb +++ b/ext/tk/lib/tk/package.rb @@ -136,4 +136,8 @@ module TkPackage def vsatisfies(version1, version2) bool(tk_call('package', 'vsatisfies', version1, version2)) end + + def prefer(setting = None) + tk_call('package', 'prefer', setting) + end end diff --git a/ext/tk/lib/tk/panedwindow.rb b/ext/tk/lib/tk/panedwindow.rb index c6cf3cd11f..ba8a7e9743 100644 --- a/ext/tk/lib/tk/panedwindow.rb +++ b/ext/tk/lib/tk/panedwindow.rb @@ -3,7 +3,7 @@ # require 'tk' -class TkPanedWindowtrue, :widgetname=>'.') - if keys # wm commands - keys.each{|k,v| - if v.kind_of? Array - new.send(k,*v) - else - new.send(k,v) - end - } - end - ROOT[0] = new - Tk_WINDOWS["."] = new - end -=end - def TkRoot.new(keys=nil, &b) + def Root.new(keys=nil, &b) unless TkCore::INTERP.tk_windows['.'] TkCore::INTERP.tk_windows['.'] = super(:without_creating=>true, :widgetname=>'.'){} @@ -62,7 +41,13 @@ class TkRoot # require 'tk' require 'tk/listbox' -class TkScrollbox use current TkListbox class list = TkListbox.new(@frame) + #scroll = Tk::Scrollbar.new(@frame) + # -> use current TkScrollbar class scroll = TkScrollbar.new(@frame) @path = list.path diff --git a/ext/tk/lib/tk/spinbox.rb b/ext/tk/lib/tk/spinbox.rb index 9a10977d12..e372c58009 100644 --- a/ext/tk/lib/tk/spinbox.rb +++ b/ext/tk/lib/tk/spinbox.rb @@ -1,12 +1,11 @@ # # tk/spinbox.rb - Tk spinbox classes -# $Date$ # by Yukihiro Matsumoto # require 'tk' require 'tk/entry' -class TkSpinbox 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) @@ -97,3 +112,6 @@ class TkSpinbox require 'tk' require 'tk/itemfont' @@ -60,7 +59,7 @@ module TkTextTagConfig private :itemconfiginfo, :current_itemconfiginfo end -class TkText 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 e5cacadc1a..f738a96ee7 100644 --- a/ext/tk/lib/tk/variable.rb +++ b/ext/tk/lib/tk/variable.rb @@ -16,11 +16,22 @@ 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]") -TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL') + TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL') if {[set st [catch {eval {ruby_cmd TkVariable callback} $args} ret]] != 0} { set idx [string first "\n\n" $ret] if {$idx > 0} { @@ -44,10 +55,10 @@ TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL') 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 @@ TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL') "\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 @@ TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL') 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$/ 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' - @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") - 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 TkVirtualEventcommand' end - kv.each{|k, v| self.protocol(k, v)} - self + kv.each{|k, v| Wm.protocol(win, k, v)} + win end + def protocols(kv=nil) + Wm.protocols(self, kv) + end + alias wm_protocols protocols TOPLEVEL_METHODCALL_OPTKEYS['protocols'] = 'protocols' - def resizable(*args) + def Wm.resizable(win, *args) if args.length == 0 - list(tk_call_without_enc('wm', 'resizable', path)).collect{|e| bool(e)} + list(tk_call_without_enc('wm', 'resizable', win.epath)).map!{|e| bool(e)} else args = args[0] if args.length == 1 && args[0].kind_of?(Array) - tk_call_without_enc('wm', 'resizable', path, *args) - self + tk_call_without_enc('wm', 'resizable', win.epath, *args) + win end end + def resizable(*args) + Wm.resizable(self, *args) + end + alias wm_resizable resizable TOPLEVEL_METHODCALL_OPTKEYS['resizable'] = 'resizable' - def sizefrom(who=None) - if who == None - r = tk_call_without_enc('wm', 'sizefrom', path) + def Wm.sizefrom(win, who=TkComm::None) + if who == TkComm::None + r = tk_call_without_enc('wm', 'sizefrom', win.epath) (r == "")? nil: r else - tk_call_without_enc('wm', 'sizefrom', path, who) - self + tk_call_without_enc('wm', 'sizefrom', win.epath, who) + win end end + def sizefrom(who=TkComm::None) + Wm.sizefrom(self, who) + end + alias wm_sizefrom sizefrom TOPLEVEL_METHODCALL_OPTKEYS['sizefrom'] = 'sizefrom' + def Wm.stackorder(win) + list(tk_call('wm', 'stackorder', win.epath)) + end def stackorder - list(tk_call('wm', 'stackorder', path)) + Wm.stackorder(self) end + alias wm_stackorder stackorder - def stackorder_isabove(win) - bool(tk_call('wm', 'stackorder', path, 'isabove', win)) + def Wm.stackorder_isabove(win, target) + bool(tk_call('wm', 'stackorder', win.epath, 'isabove', target)) + end + def Wm.stackorder_is_above(win, target) + Wm.stackorder_isabove(win, target) + end + def stackorder_isabove(target) + Wm.stackorder_isabove(self, target) end + alias stackorder_is_above stackorder_isabove + alias wm_stackorder_isabove stackorder_isabove + alias wm_stackorder_is_above stackorder_isabove - def stackorder_isbelow(win) - bool(tk_call('wm', 'stackorder', path, 'isbelow', win)) + def Wm.stackorder_isbelow(win, target) + bool(tk_call('wm', 'stackorder', win.epath, 'isbelow', target)) end + def Wm.stackorder_is_below(win, target) + Wm.stackorder_isbelow(win, target) + end + def stackorder_isbelow(target) + Wm.stackorder_isbelow(self, target) + end + alias stackorder_is_below stackorder_isbelow + alias wm_stackorder_isbelow stackorder_isbelow + alias wm_stackorder_is_below stackorder_isbelow - def state(st=nil) + def Wm.state(win, st=nil) if st - tk_call_without_enc('wm', 'state', path, st) - self + tk_call_without_enc('wm', 'state', win.epath, st) + win else - tk_call_without_enc('wm', 'state', path) + tk_call_without_enc('wm', 'state', win.epath) end end + def state(st=nil) + Wm.state(self, st) + end + alias wm_state state TOPLEVEL_METHODCALL_OPTKEYS['state'] = 'state' - def title(str=nil) + def Wm.title(win, str=nil) if str - tk_call('wm', 'title', path, str) - self + tk_call('wm', 'title', win.epath, str) + win else - tk_call('wm', 'title', path) + tk_call('wm', 'title', win.epath) end end + def title(str=nil) + Wm.title(self, str) + end + alias wm_title title TOPLEVEL_METHODCALL_OPTKEYS['title'] = 'title' - def transient(master=nil) + def Wm.transient(win, master=nil) if master - tk_call_without_enc('wm', 'transient', path, master) - self + tk_call_without_enc('wm', 'transient', win.epath, master) + win else - window(tk_call_without_enc('wm', 'transient', path)) + window(tk_call_without_enc('wm', 'transient', win.epath)) end end + def transient(master=nil) + Wm.transient(self, master) + end + alias wm_transient transient TOPLEVEL_METHODCALL_OPTKEYS['transient'] = 'transient' - def withdraw(ex = true) + def Wm.withdraw(win, ex = true) if ex - tk_call_without_enc('wm', 'withdraw', path) + tk_call_without_enc('wm', 'withdraw', win.epath) else - self.deiconify + Wm.deiconify(win) end - self + win end + def withdraw(ex = true) + Wm.withdraw(self, ex) + end + alias wm_withdraw withdraw + end + + module Wm_for_General + Wm.instance_methods.each{|m| + if (m = m.to_s) =~ /^wm_(.*)$/ + eval "def #{m}(*args); Tk::Wm.#{$1}(self, *args); end" + end + } end end diff --git a/ext/tk/lib/tkextlib/SUPPORT_STATUS b/ext/tk/lib/tkextlib/SUPPORT_STATUS index 15925cba72..cfbe274c86 100644 --- a/ext/tk/lib/tkextlib/SUPPORT_STATUS +++ b/ext/tk/lib/tkextlib/SUPPORT_STATUS @@ -83,7 +83,7 @@ BLT 2.4z http://sourceforge.net/projects/blt TkTreeCtrl CVS/Hd(2005-12-02) http://sourceforge.net/projects/tktreectrl ==> treectrl -Tile 0.7.8 +Tile 0.8.0/8.5.1 http://sourceforge.net/projects/tktable ==> tile diff --git a/ext/tk/lib/tkextlib/blt/bitmap.rb b/ext/tk/lib/tkextlib/blt/bitmap.rb index 31cf8d4229..23c6d2d064 100644 --- a/ext/tk/lib/tkextlib/blt/bitmap.rb +++ b/ext/tk/lib/tkextlib/blt/bitmap.rb @@ -13,7 +13,16 @@ module Tk::BLT TkCommandNames = ['::blt::bitmap'.freeze].freeze BITMAP_ID_TBL = TkCore::INTERP.create_table - BITMAP_ID = ['blt_bitmap_id'.freeze, '00000'.taint].freeze + + (BITMAP_ID = ['blt_bitmap_id'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + BITMAP_ID_TBL.mutex.synchronize{ BITMAP_ID_TBL.clear } + } def self.data(name) dat = tk_simple_list(tk_call('::blt::bitmap', 'data', name)) @@ -64,9 +73,13 @@ module Tk::BLT if name @id = name else - @id = BITMAP_ID.join(TkCore::INTERP._ip_id_) - BITMAP_ID[1].succ! - BITMAP_ID_TBL[@id] = self + BITMAP_ID.mutex.synchronize{ + @id = BITMAP_ID.join(TkCore::INTERP._ip_id_) + BITMAP_ID[1].succ! + } + BITMAP_ID_TBL.mutex.synchronize{ + BITMAP_ID_TBL[@id] = self + } end @path = @id diff --git a/ext/tk/lib/tkextlib/blt/busy.rb b/ext/tk/lib/tkextlib/blt/busy.rb index 4726e466f4..2f807fcd9c 100644 --- a/ext/tk/lib/tkextlib/blt/busy.rb +++ b/ext/tk/lib/tkextlib/blt/busy.rb @@ -19,7 +19,7 @@ module Tk::BLT class Shield < TkWindow def self.shield_path(win) win = window(win) unless win.kind_of?(TkWindow) - if win.kind_of?(TkToplevel) + if win.kind_of?(Tk::Toplevel) win.path + '._Busy' else win.path + '_Busy' diff --git a/ext/tk/lib/tkextlib/blt/component.rb b/ext/tk/lib/tkextlib/blt/component.rb index ad78a5430b..dd387634ee 100644 --- a/ext/tk/lib/tkextlib/blt/component.rb +++ b/ext/tk/lib/tkextlib/blt/component.rb @@ -327,13 +327,24 @@ module Tk::BLT ################# class Axis < TkObject - OBJ_ID = ['blt_chart_axis'.freeze, '00000'.taint].freeze - OBJ_TBL={} + (OBJ_ID = ['blt_chart_axis'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + AxisID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + AxisID_TBL.mutex.synchronize{ AxisID_TBL.clear } + } def self.id2obj(chart, id) cpath = chart.path - return id unless OBJ_TBL[cpath] - OBJ_TBL[cpath][id]? OBJ_TBL[cpath][id]: id + AxisID_TBL.mutex.synchronize{ + return id unless AxisID_TBL[cpath] + AxisID_TBL[cpath][id]? AxisID_TBL[cpath][id]: id + } end def self.new(chart, axis=nil, keys={}) @@ -341,12 +352,48 @@ module Tk::BLT keys = axis axis = nil end - OBJ_TBL[chart.path] = {} unless OBJ_TBL[chart.path] - return OBJ_TBL[chart.path][axis] if axis && OBJ_TBL[chart.path][axis] - super(chart, axis, keys) + if keys + keys = _symbolkey2str(keys) + not_create = keys.delete('without_creating') + else + not_create = false + end + + obj = nil + AxisID_TBL.mutex.synchronize{ + chart_path = chart.path + AxisID_TBL[chart_path] ||= {} + if axis && AxisID_TBL[chart_path][axis] + obj = AxisID_TBL[chart_path][axis] + else + (obj = self.allocate).instance_eval{ + if axis + @axis = @id = axis.to_s + else + OBJ_ID.mutex.synchronize{ + @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } + end + @path = @id + @parent = @chart = chart + @cpath = @chart.path + Axis::AxisID_TBL[@cpath][@axis] = self + unless not_create + tk_call(@chart, 'axis', 'create', @axis, keys) + return obj + end + } + end + } + + obj.configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, axis=nil, keys={}) + # dummy:: not called by 'new' method + if axis.kind_of?(Hash) keys = axis axis = nil @@ -354,13 +401,15 @@ module Tk::BLT if axis @axis = @id = axis.to_s else - @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze - OBJ_ID[1].succ! + OBJ_ID.mutex.synchronize{ + @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } end @path = @id @parent = @chart = chart @cpath = @chart.path - Axis::OBJ_TBL[@cpath][@axis] = self + # Axis::AxisID_TBL[@cpath][@axis] = self keys = _symbolkey2str(keys) unless keys.delete('without_creating') # @chart.axis_create(@axis, keys) @@ -438,17 +487,34 @@ module Tk::BLT ################# class Crosshairs < TkObject - OBJ_TBL={} + CrosshairsID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + CrosshairsID_TBL.mutex.synchronize{ CrosshairsID_TBL.clear } + } def self.new(chart, keys={}) - return OBJ_TBL[chart.path] if OBJ_TBL[chart.path] - super(chart, keys) + obj = nil + CrosshairsID_TBL.mutex.synchronize{ + unless (obj = CrosshairsID_TBL[chart.path]) + (obj = self.allocate).instance_eval{ + @parent = @chart = chart + @cpath = @chart.path + @path = @id = 'crosshairs' + Crosshairs::CrosshairsID_TBL[@cpath] = self + } + end + } + chart.crosshair_configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, keys={}) + # dummy:: not called by 'new' method + @parent = @chart = chart @cpath = @chart.path - Crosshairs::OBJ_TBL[@cpath] = self + # Crosshairs::CrosshairsID_TBL[@cpath] = self @chart.crosshair_configure(keys) unless keys.empty? @path = @id = 'crosshairs' end @@ -500,12 +566,18 @@ module Tk::BLT ElementTypeName = 'element' ElementTypeToClass = { ElementTypeName=>self } + ElementID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ ElementID_TBL.clear } + TkCore::INTERP.init_ip_env{ + ElementID_TBL.mutex.synchronize{ ElementID_TBL.clear } + } - OBJ_ID = ['blt_chart_element'.freeze, '00000'.taint].freeze - OBJ_TBL={} + (OBJ_ID = ['blt_chart_element'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } def Element.type2class(type) ElementTypeToClass[type] @@ -513,8 +585,10 @@ module Tk::BLT def Element.id2obj(chart, id) cpath = chart.path - return id unless OBJ_TBL[cpath] - OBJ_TBL[cpath][id]? OBJ_TBL[cpath][id]: id + ElementID_TBL.mutex.synchronize{ + return id unless ElementID_TBL[cpath] + ElementID_TBL[cpath][id]? ElementID_TBL[cpath][id]: id + } end def self.new(chart, element=nil, keys={}) @@ -522,14 +596,49 @@ module Tk::BLT keys = element element = nil end - OBJ_TBL[chart.path] = {} unless OBJ_TBL[chart.path] - if element && OBJ_TBL[chart.path][element] - return OBJ_TBL[chart.path][element] + if keys + keys = _symbolkey2str(keys) + not_create = keys.delete('without_creating') + else + not_create = false end - super(chart, element, keys) + + obj = nil + ElementID_TBL.mutex.synchronize{ + chart_path = chart.path + ElementID_TBL[chart_path] ||= {} + if element && ElementID_TBL[chart_path][element] + obj = ElementID_TBL[chart_path][element] + else + (obj = self.allocate).instance_eval{ + if element + @element = @id = element.to_s + else + OBJ_ID.mutex.synchronize{ + @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } + end + @path = @id + @parent = @chart = chart + @cpath = @chart.path + @typename = self.class::ElementTypeName + Element::ElementID_TBL[@cpath][@element] = self + unless not_create + tk_call(@chart, @typename, 'create', @element, keys) + return obj + end + } + end + } + + obj.configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, element=nil, keys={}) + # dummy:: not called by 'new' method + if element.kind_of?(Hash) keys = element element = nil @@ -537,14 +646,16 @@ module Tk::BLT if element @element = @id = element.to_s else - @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze - OBJ_ID[1].succ! + OBJ_ID.mutex.synchronize{ + @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } end @path = @id @parent = @chart = chart @cpath = @chart.path @typename = self.class::ElementTypeName - Element::OBJ_TBL[@cpath][@element] = self + # Element::ElementID_TBL[@cpath][@element] = self keys = _symbolkey2str(keys) unless keys.delete('without_creating') # @chart.element_create(@element, keys) @@ -622,17 +733,33 @@ module Tk::BLT ################# class GridLine < TkObject - OBJ_TBL={} + GridLineID_TBL = TkCore::INTERP.create_table + TkCore::INTERP.init_ip_env{ + GridLineID_TBL.mutex.synchronize{ GridLineID_TBL.clear } + } def self.new(chart, keys={}) - return OBJ_TBL[chart.path] if OBJ_TBL[chart.path] - super(chart, keys) + obj = nil + GridLineID_TBL.mutex.synchronize{ + unless (obj = GridLineID_TBL[chart.path]) + (obj = self.allocate).instance_eval{ + @parent = @chart = chart + @cpath = @chart.path + @path = @id = 'grid' + GridLine::GridLineID_TBL[@cpath] = self + } + end + } + chart.gridline_configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, keys={}) + # dummy:: not called by 'new' method + @parent = @chart = chart @cpath = @chart.path - GridLine::OBJ_TBL[@cpath] = self + # GridLine::GridLineID_TBL[@cpath] = self @chart.gridline_configure(keys) unless keys.empty? @path = @id = 'grid' end @@ -676,18 +803,35 @@ module Tk::BLT ################# class Legend < TkObject - OBJ_TBL={} + LegendID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + LegendID_TBL.mutex.synchronize{ LegendID_TBL.clear } + } def self.new(chart, keys={}) - return OBJ_TBL[chart.path] if OBJ_TBL[chart.path] - super(chart, keys) + obj = nil + LegenedID_TBL.mutex.synchronize{ + unless (obj = LegenedID_TBL[chart.path]) + (obj = self.allocate).instance_eval{ + @parent = @chart = chart + @cpath = @chart.path + @path = @id = 'crosshairs' + Legend::LegenedID_TBL[@cpath] = self + } + end + } + chart.legend_configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, keys={}) + # dummy:: not called by 'new' method + @parent = @chart = chart @cpath = @chart.path - Crosshairs::OBJ_TBL[@cpath] = self - @chart.crosshair_configure(keys) unless keys.empty? + # Legend::LegendID_TBL[@cpath] = self + @chart.legend_configure(keys) unless keys.empty? @path = @id = 'legend' end @@ -729,13 +873,24 @@ module Tk::BLT ################# class Pen < TkObject - OBJ_ID = ['blt_chart_pen'.freeze, '00000'.taint].freeze - OBJ_TBL={} + (OBJ_ID = ['blt_chart_pen'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + PenID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + PenID_TBL.mutex.synchronize{ PenID_TBL.clear } + } def self.id2obj(chart, id) cpath = chart.path - return id unless OBJ_TBL[cpath] - OBJ_TBL[cpath][id]? OBJ_TBL[cpath][id]: id + PenID_TBL.mutex.synchronize{ + return id unless PenID_TBL[cpath] + PenID_TBL[cpath][id]? PenID_TBL[cpath][id]: id + } end def self.new(chart, pen=nil, keys={}) @@ -743,9 +898,43 @@ module Tk::BLT keys = pen pen = nil end - OBJ_TBL[chart.path] = {} unless OBJ_TBL[chart.path] - return OBJ_TBL[chart.path][pen] if pen && OBJ_TBL[chart.path][pen] - super(chart, pen, keys) + if keys + keys = _symbolkey2str(keys) + not_create = keys.delete('without_creating') + else + not_create = false + end + + obj = nil + PenID_TBL.mutex.synchronize{ + chart_path = chart.path + PenID_TBL[chart_path] ||= {} + if pen && PenID_TBL[chart_path][pen] + obj = PenID_TBL[chart_path][pen] + else + (obj = self.allocate).instance_eval{ + if pen + @pen = @id = pen.to_s + else + OBJ_ID.mutex.synchronize{ + @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } + end + @path = @id + @parent = @chart = chart + @cpath = @chart.path + Pen::PenID_TBL[@cpath][@pen] = self + unless not_create + tk_call(@chart, 'pen', 'create', @pen, keys) + return obj + end + } + end + } + + obj.configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, pen=nil, keys={}) @@ -756,13 +945,15 @@ module Tk::BLT if pen @pen = @id = pen.to_s else - @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze - OBJ_ID[1].succ! + OBJ_ID.mutex.synchronize{ + @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze + OBJ_ID[1].succ! + } end @path = @id @parent = @chart = chart @cpath = @chart.path - Pen::OBJ_TBL[@cpath][@pen] = self + Pen::PenID_TBL[@cpath][@pen] = self keys = _symbolkey2str(keys) unless keys.delete('without_creating') # @chart.pen_create(@pen, keys) @@ -805,17 +996,34 @@ module Tk::BLT ################# class Postscript < TkObject - OBJ_TBL={} + PostscriptID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + PostscriptID_TBL.mutex.synchronize{ PostscriptID_TBL.clear } + } def self.new(chart, keys={}) - return OBJ_TBL[chart.path] if OBJ_TBL[chart.path] - super(chart, keys) + obj = nil + PostscriptID_TBL.mutex.synchronize{ + unless (obj = PostscriptID_TBL[chart.path]) + (obj = self.allocate).instance_eval{ + @parent = @chart = chart + @cpath = @chart.path + @path = @id = 'postscript' + Postscript::PostscriptID_TBL[@cpath] = self + } + end + } + chart.postscript_configure(keys) if obj && ! keys.empty? + obj end def initialize(chart, keys={}) + # dummy:: not called by 'new' method + @parent = @chart = chart @cpath = @chart.path - Postscript::OBJ_TBL[@cpath] = self + # Postscript::PostscriptID_TBL[@cpath] = self @chart.postscript_configure(keys) unless keys.empty? @path = @id = 'postscript' end @@ -870,7 +1078,9 @@ module Tk::BLT MarkerTypeToClass = {} MarkerID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ MarkerID_TBL.clear } + TkCore::INTERP.init_ip_env{ + MarkerID_TBL.mutex.synchronize{ MarkerID_TBL.clear } + } def Marker.type2class(type) MarkerTypeToClass[type] @@ -878,8 +1088,13 @@ module Tk::BLT def Marker.id2obj(chart, id) cpath = chart.path - return id unless MarkerID_TBL[cpath] - MarkerID_TBL[cpath][id]? MarkerID_TBL[cpath][id]: id + MarkerID_TBL.mutex.synchronize{ + if MarkerID_TBL[cpath] + MarkerID_TBL[cpath][id]? MarkerID_TBL[cpath][id]: id + else + id + end + } end def self._parse_create_args(keys) @@ -943,10 +1158,10 @@ module Tk::BLT @parent = @chart = chart @cpath = chart.path @id = id - unless Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] - Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] = {} - end - Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self + Tk::BLT::PlotComponent::Marker::MarkerID_TBL.mutex.synchronize{ + Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] ||= {} + Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self + } } obj end @@ -956,10 +1171,10 @@ module Tk::BLT @cpath = parent.path @path = @id = create_self(*args) # an integer number as 'item id' - unless Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] - Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] = {} - end - Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self + Tk::BLT::PlotComponent::Marker::MarkerID_TBL.mutex.synchronize{ + Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] ||= {} + Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self + } end def create_self(*args) self.class.create(@chart, *args) # return an integer as 'item id' @@ -1037,14 +1252,14 @@ module Tk::BLT ################# def __destroy_hook__ - Axis::OBJ_TBL.delete(@path) - Crosshairs::OBJ_TBL.delete(@path) - Element::OBJ_TBL.delete(@path) - GridLine::OBJ_TBL.delete(@path) - Legend::OBJ_TBL.delete(@path) - Pen::OBJ_TBL.delete(@path) - Postscript::OBJ_TBL.delete(@path) - Marker::OBJ_TBL.delete(@path) + Axis::AxisID_TBL.delete(@path) + Crosshairs::CrosshairsID_TBL.delete(@path) + Element::ElementID_TBL.delete(@path) + GridLine::GridLineID_TBL.delete(@path) + Legend::LegendID_TBL.delete(@path) + Pen::PenID_TBL.delete(@path) + Postscript::PostscriptID_TBL.delete(@path) + Marker::MarkerID_TBL.delete(@path) super() end diff --git a/ext/tk/lib/tkextlib/blt/dragdrop.rb b/ext/tk/lib/tkextlib/blt/dragdrop.rb index 68fb9e591a..98b1a4832f 100644 --- a/ext/tk/lib/tkextlib/blt/dragdrop.rb +++ b/ext/tk/lib/tkextlib/blt/dragdrop.rb @@ -81,6 +81,22 @@ module Tk::BLT nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL) def self.ret_val(val) @@ -107,6 +123,22 @@ module Tk::BLT nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL) def self.ret_val(val) @@ -145,6 +177,22 @@ module Tk::BLT nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL) end diff --git a/ext/tk/lib/tkextlib/blt/eps.rb b/ext/tk/lib/tkextlib/blt/eps.rb index 586a42470c..0dba87a7cc 100644 --- a/ext/tk/lib/tkextlib/blt/eps.rb +++ b/ext/tk/lib/tkextlib/blt/eps.rb @@ -14,7 +14,7 @@ module Tk::BLT end end -class TkCanvas +class Tk::Canvas alias __BLT_EPS_item_strval_optkeys __item_strval_optkeys def __item_strval_optkeys(id) __BLT_EPS_item_strval_optkeys(id) + [ diff --git a/ext/tk/lib/tkextlib/blt/tabset.rb b/ext/tk/lib/tkextlib/blt/tabset.rb index c26b6ee001..1a0f312c4c 100644 --- a/ext/tk/lib/tkextlib/blt/tabset.rb +++ b/ext/tk/lib/tkextlib/blt/tabset.rb @@ -12,14 +12,26 @@ module Tk::BLT include TkTreatItemFont TabID_TBL = TkCore::INTERP.create_table - TabsetTab_ID = ['blt_tabset_tab'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TabID_TBL.clear } + (TabsetTab_ID = ['blt_tabset_tab'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + TabID_TBL.mutex.synchronize{ TabID_TBL.clear } + } def self.id2obj(tabset, id) tpath = tabset.path - return id unless TabID_TBL[tpath] - TabID_TBL[tpath][id]? TabID_TBL[tpath]: id + TabID_TBL.mutex.synchronize{ + if TabID_TBL[tpath] + TabID_TBL[tpath][id]? TabID_TBL[tpath]: id + else + id + end + } end def self.new(parent, pos=nil, name=nil, keys={}) @@ -32,12 +44,20 @@ module Tk::BLT keys = name name = nil end - - if name && TabID_TBL[parent.path] && TabID_TBL[parent.path][name] - TabID_TBL[parent.path][name] - else - super(parent, pos, name, keys) - end + obj = nil + TabID_TBL.mutex.synchronize{ + if name && TabID_TBL[parent.path] && TabID_TBL[parent.path][name] + obj = TabID_TBL[parent.path][name] + obj.configure if keys && ! keys.empty? + else + (obj = self.allocate).instance_eval{ + initialize(parent, pos, name, keys) + TabID_TBL[@tpath] = {} unless TabID_TBL[@tpath] + TabID_TBL[@tpath][@id] = self + } + end + } + obj end def initialize(parent, pos, name, keys) @@ -45,9 +65,6 @@ module Tk::BLT @tpath = parent.path if name @path = @id = name - TabID_TBL[@tpath] = {} unless TabID_TBL[@tpath] - TabID_TBL[@tpath][@id] = self - unless (list(tk_call(@tpath, 'tab', 'names', @id)).empty?) if pos idx = tk_call(@tpath, 'index', '-name', @id) @@ -58,18 +75,18 @@ module Tk::BLT end end tk_call(@tpath, 'tab', 'configure', @id, keys) - return + else + pos = 'end' unless pos + tk_call(@tpath, 'insert', pos, @id, keys) end - else - @path = @id = TabsetTab_ID.join(TkCore::INTERP._ip_id_) - TabID_TBL[@tpath] = {} unless TabID_TBL[@tpath] - TabID_TBL[@tpath][@id] = self - TabsetTab_ID[1].succ! + TabsetTab_ID.mutex.synchronize{ + @path = @id = TabsetTab_ID.join(TkCore::INTERP._ip_id_) + TabsetTab_ID[1].succ! + } + pos = 'end' unless pos + tk_call(@tpath, 'insert', pos, @id, keys) end - - pos = 'end' unless pos - tk_call(@tpath, 'insert', pos, @id, keys) end #def bind(context, cmd=Proc.new, *args) @@ -123,7 +140,9 @@ module Tk::BLT def delete() @t.delete(@id) - TabID_TBL[@tpath].delete(@id) + TabID_TBL.mutex.synchronize{ + TabID_TBL[@tpath].delete(@id) + } self end @@ -184,7 +203,9 @@ module Tk::BLT WidgetClassNames[WidgetClassName] = self def __destroy_hook__ - Tk::BLT::Tabset::Tab::TabID_TBL.delete(@path) + Tk::BLT::Tabset::Tab::TabID_TBL.mutex.synchronize{ + Tk::BLT::Tabset::Tab::TabID_TBL.delete(@path) + } end ######################################## @@ -291,11 +312,15 @@ module Tk::BLT def delete(first, last=None) tk_send('delete', tagindex(first), tagindex(last)) if first.kind_of?(Tk::BLT::Tabset::Tab) - TabID_TBL[@path].delete(first.id) + TabID_TBL.mutex.synchronize{ + TabID_TBL[@path].delete(first.id) + } end # middle tabs of the range are unknown if last.kind_of?(Tk::BLT::Tabset::Tab) - TabID_TBL[@path].delete(last.id) + TabID_TBL.mutex.synchronize{ + TabID_TBL[@path].delete(last.id) + } end self end diff --git a/ext/tk/lib/tkextlib/blt/tile/button.rb b/ext/tk/lib/tkextlib/blt/tile/button.rb index dd715c8b98..2e0863cfbe 100644 --- a/ext/tk/lib/tkextlib/blt/tile/button.rb +++ b/ext/tk/lib/tkextlib/blt/tile/button.rb @@ -9,7 +9,7 @@ require 'tkextlib/blt/tile.rb' module Tk::BLT module Tile - class Button < TkButton + class Button < Tk::Button TkCommandNames = ['::blt::tile::button'.freeze].freeze end end diff --git a/ext/tk/lib/tkextlib/blt/tile/checkbutton.rb b/ext/tk/lib/tkextlib/blt/tile/checkbutton.rb index ad58999d86..da230b5925 100644 --- a/ext/tk/lib/tkextlib/blt/tile/checkbutton.rb +++ b/ext/tk/lib/tkextlib/blt/tile/checkbutton.rb @@ -9,7 +9,7 @@ require 'tkextlib/blt/tile.rb' module Tk::BLT module Tile - class CheckButton < TkCheckButton + class CheckButton < Tk::CheckButton TkCommandNames = ['::blt::tile::checkbutton'.freeze].freeze end Checkbutton = CheckButton diff --git a/ext/tk/lib/tkextlib/blt/tile/frame.rb b/ext/tk/lib/tkextlib/blt/tile/frame.rb index 10469fd35f..5434af4b72 100644 --- a/ext/tk/lib/tkextlib/blt/tile/frame.rb +++ b/ext/tk/lib/tkextlib/blt/tile/frame.rb @@ -9,7 +9,7 @@ require 'tkextlib/blt/tile.rb' module Tk::BLT module Tile - class Frame < TkFrame + class Frame < Tk::Frame TkCommandNames = ['::blt::tile::frame'.freeze].freeze end end diff --git a/ext/tk/lib/tkextlib/blt/tile/label.rb b/ext/tk/lib/tkextlib/blt/tile/label.rb index ec67babd58..f370c1403b 100644 --- a/ext/tk/lib/tkextlib/blt/tile/label.rb +++ b/ext/tk/lib/tkextlib/blt/tile/label.rb @@ -9,7 +9,7 @@ require 'tkextlib/blt/tile.rb' module Tk::BLT module Tile - class Label < TkLabel + class Label < Tk::Label TkCommandNames = ['::blt::tile::label'.freeze].freeze end end diff --git a/ext/tk/lib/tkextlib/blt/tile/radiobutton.rb b/ext/tk/lib/tkextlib/blt/tile/radiobutton.rb index 2316923b19..814f9a5cc4 100644 --- a/ext/tk/lib/tkextlib/blt/tile/radiobutton.rb +++ b/ext/tk/lib/tkextlib/blt/tile/radiobutton.rb @@ -9,7 +9,7 @@ require 'tkextlib/blt/tile.rb' module Tk::BLT module Tile - class RadioButton < TkRadioButton + class RadioButton < Tk::RadioButton TkCommandNames = ['::blt::tile::radiobutton'.freeze].freeze end Radiobutton = RadioButton diff --git a/ext/tk/lib/tkextlib/blt/tile/scrollbar.rb b/ext/tk/lib/tkextlib/blt/tile/scrollbar.rb index ba3bf316f0..2ae871d518 100644 --- a/ext/tk/lib/tkextlib/blt/tile/scrollbar.rb +++ b/ext/tk/lib/tkextlib/blt/tile/scrollbar.rb @@ -9,7 +9,7 @@ require 'tkextlib/blt/tile.rb' module Tk::BLT module Tile - class Scrollbar < TkScrollbar + class Scrollbar < Tk::Scrollbar TkCommandNames = ['::blt::tile::scrollbar'.freeze].freeze end end diff --git a/ext/tk/lib/tkextlib/blt/tile/toplevel.rb b/ext/tk/lib/tkextlib/blt/tile/toplevel.rb index 6cc2c91415..76d5f86b1b 100644 --- a/ext/tk/lib/tkextlib/blt/tile/toplevel.rb +++ b/ext/tk/lib/tkextlib/blt/tile/toplevel.rb @@ -9,7 +9,7 @@ require 'tkextlib/blt/tile.rb' module Tk::BLT module Tile - class Toplevel < TkToplevel + class Toplevel < Tk::Toplevel TkCommandNames = ['::blt::tile::toplevel'.freeze].freeze end end diff --git a/ext/tk/lib/tkextlib/blt/tree.rb b/ext/tk/lib/tkextlib/blt/tree.rb index 07dc7ef7e8..77b85f1717 100644 --- a/ext/tk/lib/tkextlib/blt/tree.rb +++ b/ext/tk/lib/tkextlib/blt/tree.rb @@ -12,53 +12,77 @@ module Tk::BLT ################################### - class Node < TkObject + class Node < TkObject TreeNodeID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ TreeNodeID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + TreeNodeID_TBL.mutex.synchronize{ TreeNodeID_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless TreeNodeID_TBL[tpath] - if TreeNodeID_TBL[tpath][id] - TreeNodeID_TBL[tpath][id] - else - begin - self.new(tree, nil, 'node'=>Integer(id)) - rescue + TreeNodeID_TBL.mutex.synchronize{ + if TreeNodeID_TBL[tpath] + if TreeNodeID_TBL[tpath][id] + TreeNodeID_TBL[tpath][id] + else + begin + # self.new(tree, nil, 'node'=>Integer(id)) + id = Integer(id) + if bool(tk_call(@tpath, 'exists', id)) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = tpath + @path = @id = id + TreeNodeID_TBL[@tpath] = {} unless TreeNodeID_TBL[@tpath] + TreeNodeID_TBL[@tpath][@id] = self + } + obj + else + id + end + rescue + id + end + end + else id end - end + } end def self.new(tree, parent, keys={}) keys = _symbolkey2str(keys) tpath = tree.path - if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id]) - keys.delete('node') - tk_call(tree.path, 'move', id, parent, keys) if parent - return obj - end + TreeNodeID_TBL.mutex.synchronize{ + TreeNodeID_TBL[tpath] ||= {} + if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id]) + keys.delete('node') + tk_call(tree.path, 'move', id, parent, keys) if parent + return obj + end - super(tree, parent, keys) + (obj = self.allocate).instance_eval{ + initialize(tree, parent, keys) + TreeNodeID_TBL[tpath][@id] = self + } + obj + } end def initialize(tree, parent, keys={}) @parent = @tree = tree @tpath = @parent.path - parent = tk_call(@tpath, 'root') unless parent - if (id = keys['node']) && bool(tk_call(@tpath, 'exists', id)) @path = @id = id keys.delete('node') tk_call(@tpath, 'move', @id, parent, keys) if parent else + parent = tk_call(@tpath, 'root') unless parent @path = @id = tk_call(@tpath, 'insert', parent, keys) end - - TreeNodeID_TBL[@tpath] = {} unless TreeNodeID_TBL[@tpath] - TreeNodeID_TBL[@tpath][@id] = self end def id @@ -243,17 +267,42 @@ module Tk::BLT class Tag < TkObject TreeTagID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ TreeTagID_TBL.clear } - TreeTag_ID = ['blt_tree_tag'.freeze, '00000'.taint].freeze + + TkCore::INTERP.init_ip_env{ + TreeTagID_TBL.mutex.synchronize{ TreeTagID_TBL.clear } + } + + (TreeTag_ID = ['blt_tree_tag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } def self.id2obj(tree, id) tpath = tree.path - return id unless TreeTagID_TBL[tpath] - if TreeTagID_TBL[tpath][id] - TreeTagID_TBL[tpath][id] - else - self.new(tree, id) - end + TreeTagID_TBL.mutex.synchronize{ + if TreeTagID_TBL[tpath] + if TreeTagID_TBL[tpath][id] + TreeTagID_TBL[tpath][id] + else + begin + # self.new(tree, id) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = id.dup.freeze if id + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } + obj + rescue + id + end + end + else + id + end + } end def initialize(tree, tag_str = nil) @@ -263,12 +312,15 @@ module Tk::BLT if tag_str @path = @id = tag_str.dup.freeze else - @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_) - TreeTagID_TBL[@id] = self - TreeTag_ID[1].succ! + TreeTag_ID.mutex.synchronize{ + @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_) + TreeTag_ID[1].succ! + } end - TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] - TreeTagID_TBL[@tpath][@id] = self + TreeTagID_TBL.mutex.synchronize{ + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } end def id @@ -287,7 +339,9 @@ module Tk::BLT def forget() tk_call(@tpath, 'tag', 'forget', @id) - TreeTagID_TBL[@tpath].delete(@id) + TreeTagID_TBL.mutex.synchronize{ + TreeTagID_TBL[@tpath].delete(@id) + } self end @@ -312,44 +366,63 @@ module Tk::BLT class Notify < TkObject NotifyID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ NotifyID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + NotifyID_TBL.mutex.synchronize{ NotifyID_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless NotifyID_TBL[tpath] - if NotifyID_TBL[tpath][id] - NotifyID_TBL[tpath][id] - else - begin - self.new([tree, id]) - rescue - id + NotifyID_TBL.mutex.synchronize{ + if NotifyID_TBL[tpath] + if NotifyID_TBL[tpath][id] + NotifyID_TBL[tpath][id] + else + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = id + NotifyID_TBL[@tpath] ||= {} + NotifyID_TBL[@tpath][@id] = self + } + obj + end + else + return id end - end + } end def self.new(tree, *args, &b) - if tree.kind_of?(Array) - # not create - if obj = NotifyID_TBL[tree[0].path][tree[1]] + NotifyID_TBL.mutex.synchronize{ + if tree.kind_of?(Array) + # not create + tpath = tree[0].path + NotifyID_TBL[tpath] ||= {} + unless (obj = NotifyID_TBL[tpath][tree[1]]) + (NotifyID_TBL[tpath][tree[1]] = + obj = self.allocate).instance_eval{ + @parent = @tree = tree[0] + @tpath = @parent.path + @path = @id = tree[1] + } + end return obj - else - return super(false, tree[0], tree[1]) end - end - super(true, tree, *args, &b) + (obj = self.allocate).instance_eval{ + initialize(tree, *args, &b) + NotifyID_TBL[@tpath] ||= {} + NotifyID_TBL[@tpath][@id] = self + } + return obj + } end - def initialize(create, tree, *args, &b) + def initialize(tree, *args, &b) @parent = @tree = tree @tpath = @parent.path - unless create - @path = @id = args[0] - return - end - # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) if TkComm._callback_entry?(args[0]) cmd = args.shift @@ -378,7 +451,9 @@ module Tk::BLT def delete() tk_call(@tpath, 'notify', 'delete', @id) - NotifyID_TBL[tpath].delete(@id) + NotifyID_TBL.mutex.synchronize{ + NotifyID_TBL[@tpath].delete(@id) + } self end @@ -395,44 +470,69 @@ module Tk::BLT class Trace < TkObject TraceID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ TraceID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + TraceID_TBL.mutex.synchronize{ TraceID_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless TraceID_TBL[tpath] - if TraceID_TBL[tpath][id] - TraceID_TBL[tpath][id] - else - begin - self.new([tree, id]) - rescue + TraceID_TBL.mutex.synchronize{ + if TraceID_TBL[tpath] + if TraceID_TBL[tpath][id] + TraceID_TBL[tpath][id] + else + begin + # self.new([tree, id]) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = node # == traceID + TraceID_TBL[@tpath] ||= {} + TraceID_TBL[@tpath][@id] = self + } + obj + rescue + id + end + end + else id end - end + } end def self.new(tree, *args, &b) - if tree.kind_of?(Array) - # not create - if obj = TraceID_TBL[tree[0].path][tree[1]] + TraceID_TBL.mutex.synchronize{ + if tree.kind_of?(Array) + # not create + tpath = tree[0].path + TraceID_TBL[tpath] ||= {} + unless (obj = TraceID_TBL[tpath][tree[1]]) + (TraceID_TBL[tpath][tree[1]] = + obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = tree[1] # == traceID + } + end return obj - else - return super(false, tree[0], tree[1]) end - end - super(true, tree, *args, &b) + # super(true, tree, *args, &b) + (obj = self.allocate).instance_eval{ + initialize(tree, *args, &b) + TraceID_TBL[@tpath] ||= {} + TraceID_TBL[@tpath][@id] = self + } + return obj + } end - def initialize(create, tree, node, key, opts, cmd=nil, &b) + def initialize(tree, node, key, opts, cmd=nil, &b) @parent = @tree = tree @tpath = @parent.path - unless create - @path = @id = node # == traceID - return - end - if !cmd if b cmd = Proc.new(&b) @@ -459,7 +559,9 @@ module Tk::BLT def delete() tk_call(@tpath, 'trace', 'delete', @id) - TraceID_TBL[tpath].delete(@id) + TraceID_TBL.mutex.synchronize{ + TraceID_TBL[tpath].delete(@id) + } self end @@ -475,7 +577,12 @@ module Tk::BLT ################################### TreeID_TBL = TkCore::INTERP.create_table - Tree_ID = ['blt_tree'.freeze, '00000'.taint].freeze + + (Tree_ID = ['blt_tree'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } def __keyonly_optkeys { @@ -498,7 +605,9 @@ module Tk::BLT end def self.id2obj(id) - TreeID_TBL[id]? TreeID_TBL[id]: id + TreeID_TBL.mutex.synchronize{ + TreeID_TBL[id]? TreeID_TBL[id]: id + } end def self.names(pat = None) @@ -513,27 +622,45 @@ module Tk::BLT end def self.new(name = nil) - return TreeID_TBL[name] if name && TreeID_TBL[name] - super(name) + TreeID_TBL.mutex.synchronize{ + if name && TreeID_TBL[name] + TreeID_TBL[name] + else + (obj = self.allocate).instance_eval{ + initialize(name) + TreeID_TBL[@id] = self + } + obj + end + } end def initialzie(name = nil) if name @path = @id = name else - @path = @id = Tree_ID.join(TkCore::INTERP._ip_id_) - TreeID_TBL[@id] = self - Tree_ID[1].succ! + Tree_ID.mutex.synchronize{ + @path = @id = Tree_ID.join(TkCore::INTERP._ip_id_) + Tree_ID[1].succ! + } end - TreeID_TBL[@id] = self + tk_call('::blt::tree', 'create', @id) end def __destroy_hook__ - Tk::BLT::Tree::Node::TreeNodeID_TBL.delete(@path) - Tk::BLT::Tree::Tag::TreeTagID_TBL.delete(@path) - Tk::BLT::Tree::Notify::NotifyID_TBL.delete(@path) - Tk::BLT::Tree::Trace::TraceID_TBL.delete(@path) + Tk::BLT::Tree::Node::TreeNodeID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Node::TreeNodeID_TBL.delete(@path) + } + Tk::BLT::Tree::Tag::TreeTagID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Tag::TreeTagID_TBL.delete(@path) + } + Tk::BLT::Tree::Notify::NotifyID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Notify::NotifyID_TBL.delete(@path) + } + Tk::BLT::Tree::Trace::TraceID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Trace::TraceID_TBL.delete(@path) + } end def tagid(tag) @@ -592,12 +719,14 @@ module Tk::BLT def delete(*nodes) tk_call('::blt::tree', 'delete', *(nodes.collect{|node| tagid(node)})) - nodes.each{|node| - if node.kind_of?(Tk::BLT::Tree::Node) - Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.id) - else - Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.to_s) - end + Tk::BLT::Tree::Node::TreeNodeID_TBL.mutex.synchronize{ + nodes.each{|node| + if node.kind_of?(Tk::BLT::Tree::Node) + Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.id) + else + Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.to_s) + end + } } self end @@ -728,7 +857,9 @@ module Tk::BLT id.delete else tk_call(@path, 'notify', 'delete', id) - Tk::BLT::Tree::Notify::NotifyID_TBL[@path].delete(id.to_s) + Tk::BLT::Tree::Notify::NotifyID_TBL.mutex.synchronize{ + Tk::BLT::Tree::Notify::NotifyID_TBL[@path].delete(id.to_s) + } end self end @@ -835,7 +966,9 @@ module Tk::BLT def tag_forget(tag) tag = tag.id if tag.kind_of?(Tk::BLT::Tree::Tag) tk_call(@path, 'tag', 'forget', tag) - TreeTagID_TBL[@path].delete(tag) + TreeTagID_TBL.mutex.synchronize{ + TreeTagID_TBL[@path].delete(tag) + } self end @@ -889,7 +1022,9 @@ module Tk::BLT def trace_delete(*args) args = args.collect{|id| tagid(id)} tk_call(@path, 'trace', 'delete', *args) - args.each{|id| Tk::BLT::Tree::Trace::TraceID_TBL[@path].delete(id.to_s)} + Tk::BLT::Tree::Trace::TraceID_TBL.mutex.synchronize{ + args.each{|id| Tk::BLT::Tree::Trace::TraceID_TBL[@path].delete(id.to_s)} + } self end diff --git a/ext/tk/lib/tkextlib/blt/treeview.rb b/ext/tk/lib/tkextlib/blt/treeview.rb index 0343d28b9c..fc890614be 100644 --- a/ext/tk/lib/tkextlib/blt/treeview.rb +++ b/ext/tk/lib/tkextlib/blt/treeview.rb @@ -239,6 +239,22 @@ class Tk::BLT::Treeview nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -273,8 +289,12 @@ class Tk::BLT::Treeview ######################## def __destroy_hook__ - Tk::BLT::Treeview::Node::TreeNodeID_TBL.delete(@path) - Tk::BLT::Treeview::Tag::TreeTagID_TBL.delete(@path) + Tk::BLT::Treeview::Node::TreeNodeID_TBL.mutex.synchronize{ + Tk::BLT::Treeview::Node::TreeNodeID_TBL.delete(@path) + } + Tk::BLT::Treeview::Tag::TreeTagID_TBL.mutex.synchronize{ + Tk::BLT::Treeview::Tag::TreeTagID_TBL.delete(@path) + } end def tagid(tag) @@ -472,6 +492,22 @@ class Tk::BLT::Treeview nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -967,22 +1003,47 @@ class Tk::BLT::Treeview::Node < TkObject include Tk::BLT::Treeview::TagOrID_Methods TreeNodeID_TBL = TkCore::INTERP.create_table - TreeNode_ID = ['blt_treeview_node'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TreeNodeID_TBL.clear } + (TreeNode_ID = ['blt_treeview_node'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + TreeNodeID_TBL.mutex.synchronize{ TreeNodeID_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless TreeNodeID_TBL[tpath] - if TreeNodeID_TBL[tpath][id] - TreeNodeID_TBL[tpath][id] - else - begin - self.new(tree, nil, nil, 'node'=>Integer(id)) - rescue + TreeNodeID_TBL.mutex.synchronize{ + if TreeNodeID_TBL[tpath] + if TreeNodeID_TBL[tpath][id] + TreeNodeID_TBL[tpath][id] + else + begin + # self.new(tree, nil, nil, 'node'=>Integer(id)) + unless (tk_call(@tpath, 'get', id)).empty? + id = Integer(id) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = id + TreeNodeID_TBL[@tpath] ||= {} + TreeNodeID_TBL[@tpath][@id] = self + } + obj + else + id + end + rescue + id + end + end + else id end - end + } end def self.new(tree, pos, parent=nil, keys={}) @@ -994,13 +1055,21 @@ class Tk::BLT::Treeview::Node < TkObject keys = _symbolkey2str(keys) tpath = tree.path - if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id]) - keys.delete('node') - tk_call(tree.path, 'move', id, pos, parent) if parent - return obj - end + TreeNodeID_TBL.mutex.synchronize{ + TreeNodeID_TBL[tpath] ||= {} + if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id]) + keys.delete('node') + tk_call(tree.path, 'move', id, pos, parent) if parent + return obj + end - super(tree, pos, parent, keys) + #super(tree, pos, parent, keys) + (obj = self.allocate).instance_eval{ + initialize(tree, pos, parent, keys) + TreeNodeID_TBL[tpath][@id] = self + } + obj + } end def initialize(tree, pos, parent, keys) @@ -1008,11 +1077,18 @@ class Tk::BLT::Treeview::Node < TkObject @tpath = @parent.path if (id = keys['node']) + # if tk_call(@tpath, 'get', id).empty? + # fail RuntimeError, "not exist the node '#{id}'" + # end @path = @id = id tk_call(@tpath, 'move', @id, pos, tagid(parent)) if parent + configure(keys) if keys && ! keys.empty? else - name = TreeNode_ID.join(TkCore::INTERP._ip_id_).freeze - TreeNode_ID[1].succ! + name = nil + TreeNode_ID.mutex.synchronize{ + name = TreeNode_ID.join(TkCore::INTERP._ip_id_).freeze + TreeNode_ID[1].succ! + } at = keys.delete['at'] @@ -1035,9 +1111,6 @@ class Tk::BLT::Treeview::Node < TkObject end @path = @id end - - TreeNodeID_TBL[@tpath] = {} unless TreeNodeID_TBL[@tpath] - TreeNodeID_TBL[@tpath][@id] = self end def id @@ -1051,37 +1124,66 @@ class Tk::BLT::Treeview::Tag < TkObject include Tk::BLT::Treeview::TagOrID_Methods TreeTagID_TBL = TkCore::INTERP.create_table - TreeTag_ID = ['blt_treeview_tag'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TreeTagID_TBL.clear } + (TreeTag_ID = ['blt_treeview_tag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } - def self.id2obj(tree, id) + TkCore::INTERP.init_ip_env{ + TreeTagID_TBL.mutex.synchronize{ TreeTagID_TBL.clear } + } + + def self.id2obj(tree, name) tpath = tree.path - return id unless TreeTagID_TBL[tpath] - if TreeTagID_TBL[tpath][id] - TreeTagID_TBL[tpath][id] - else - begin - self.new(tree, nil, nil, 'name'=>Integer(id)) - rescue + TreeTagID_TBL.mutex.synchronize{ + if TreeTagID_TBL[tpath] + if TreeTagID_TBL[tpath][name] + TreeTagID_TBL[tpath][name] + else + #self.new(tree, name) + (obj = self.allocate).instance_eval{ + @parent = @tree = tree + @tpath = @parent.path + @path = @id = name + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } + obj + end + else id end - end + } end def self.new_by_name(tree, name, *ids) - if (obj = TreeTagID_TBL[tree.path][name]) - return obj - end - new([tree, name], ids) + TreeTagID_TBL.mutex.synchronize{ + unless (obj = TreeTagID_TBL[tree.path][name]) + (obj = self.allocate).instance_eval{ + initialize(tree, name, ids) + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } + end + obj + } end def self.new(tree, *ids) - if tree.kind_of?(Array) - super(tree[0], tree[1], ids) - else - super(tree, nil, ids) - end + TreeTagID_TBL.mutex.synchronize{ + (obj = self.allocate).instance_eval{ + if tree.kind_of?(Array) + initialize(tree[0], tree[1], ids) + else + initialize(tree, nil, ids) + end + TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] + TreeTagID_TBL[@tpath][@id] = self + } + obj + } end def initialize(tree, name, ids) @@ -1091,13 +1193,12 @@ class Tk::BLT::Treeview::Tag < TkObject if name @path = @id = name else - @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_).freeze - TreeTag_ID[1].succ! + TreeTag_ID.mutex.synchronize{ + @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_).freeze + TreeTag_ID[1].succ! + } end - TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath] - TreeTagID_TBL[@tpath][@id] = self - unless ids.empty? tk_call(@tpath, 'tag', 'add', @id, *(ids.collect{|id| tagid(id)})) end diff --git a/ext/tk/lib/tkextlib/blt/vector.rb b/ext/tk/lib/tkextlib/blt/vector.rb index 540b6b9102..76c12a24e8 100644 --- a/ext/tk/lib/tkextlib/blt/vector.rb +++ b/ext/tk/lib/tkextlib/blt/vector.rb @@ -23,14 +23,17 @@ module Tk::BLT end def self.names(pat=None) - simplelist(tk_call('::blt::vector', 'names', pat)).collect{|name| - if TkVar_ID_TBL[name] - TkVar_ID_TBL[name] - elsif name[0..1] == '::' && TkVar_ID_TBL[name[2..-1]] - TkVar_ID_TBL[name[2..-1]] - else - name - end + list = simplelist(tk_call('::blt::vector', 'names', pat)) + TkVar_ID_TBL.mutex.synchronize{ + list.collect{|name| + if TkVar_ID_TBL[name] + TkVar_ID_TBL[name] + elsif name[0..1] == '::' && TkVar_ID_TBL[name[2..-1]] + TkVar_ID_TBL[name[2..-1]] + else + name + end + } } end @@ -53,7 +56,9 @@ module Tk::BLT "#auto", *hash_kv(keys)) end - TkVar_ID_TBL[@id] = self + TkVar_ID_TBL.mutex.synchronize{ + TkVar_ID_TBL[@id] = self + } @def_default = false @default_val = nil @@ -221,13 +226,21 @@ module Tk::BLT class VectorAccess < Vector def self.new(name) - return TkVar_ID_TBL[name] if TkVar_ID_TBL[name] - super(name, size=nil, keys={}) + TkVar_ID_TBL.mutex.synchronize{ + if TkVar_ID_TBL[name] + TkVar_ID_TBL[name] + else + (obj = self.allocate).instance_eval{ + initialize(name) + TkVar_ID_TBL[@id] = self + } + obj + end + } end def initialize(vec_name) @id = vec_name - TkVar_ID_TBL[@id] = self @def_default = false @default_val = nil diff --git a/ext/tk/lib/tkextlib/blt/watch.rb b/ext/tk/lib/tkextlib/blt/watch.rb index ae5e50f126..2daf417e0b 100644 --- a/ext/tk/lib/tkextlib/blt/watch.rb +++ b/ext/tk/lib/tkextlib/blt/watch.rb @@ -13,11 +13,23 @@ module Tk::BLT TkCommandNames = ['::blt::watch'.freeze].freeze WATCH_ID_TBL = TkCore::INTERP.create_table - BLT_WATCH_ID = ['blt_watch_id'.freeze, '00000'.taint].freeze + + (BLT_WATCH_ID = ['blt_watch_id'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + WATCH_ID_TBL.mutex.synchronize{ WATCH_ID_TBL.clear } + } def self.names(state = None) - tk_split_list(tk_call('::blt::watch', 'names', state)).collect{|name| - WATCH_ID_TBL[name] || name + lst = tk_split_list(tk_call('::blt::watch', 'names', state)) + WATCH_ID_TBL.mutex.synchronize{ + lst.collect{|name| + WATCH_ID_TBL[name] || name + } } end @@ -45,13 +57,17 @@ module Tk::BLT if name @id = name.to_s else - @id = BLT_WATCH_ID.join(TkCore::INTERP._ip_id_) - BLT_WATCH_ID[1].succ! + BLT_WATCH_ID.mutex.synchronize{ + @id = BLT_WATCH_ID.join(TkCore::INTERP._ip_id_) + BLT_WATCH_ID[1].succ! + } end @path = @id - WATCH_ID_TBL[@id] = self + WATCH_ID_TBL.mutex.synchronize{ + WATCH_ID_TBL[@id] = self + } tk_call('::blt::watch', 'create', @id, *hash_kv(keys)) end diff --git a/ext/tk/lib/tkextlib/bwidget/button.rb b/ext/tk/lib/tkextlib/bwidget/button.rb index 4a9d4a7948..8f3087d098 100644 --- a/ext/tk/lib/tkextlib/bwidget/button.rb +++ b/ext/tk/lib/tkextlib/bwidget/button.rb @@ -9,7 +9,7 @@ require 'tkextlib/bwidget.rb' module Tk module BWidget - class Button < TkButton + class Button < Tk::Button end end end diff --git a/ext/tk/lib/tkextlib/bwidget/buttonbox.rb b/ext/tk/lib/tkextlib/bwidget/buttonbox.rb index ef999239f9..8d6d212189 100644 --- a/ext/tk/lib/tkextlib/bwidget/buttonbox.rb +++ b/ext/tk/lib/tkextlib/bwidget/buttonbox.rb @@ -31,7 +31,7 @@ class Tk::BWidget::ButtonBox name = tagOrId[:name] return index(name) unless name.empty? end - if tagOrId.kind_of?(TkButton) + if tagOrId.kind_of?(Tk::Button) return index(tagOrId[:text]) end # index(tagOrId.to_s) @@ -40,7 +40,13 @@ class Tk::BWidget::ButtonBox def add(keys={}, &b) win = window(tk_send('add', *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end @@ -54,7 +60,7 @@ class Tk::BWidget::ButtonBox name = idx[:name] idx = name unless name.empty? end - if idx.kind_of?(TkButton) + if idx.kind_of?(Tk::Button) idx = idx[:text] end number(tk_send('index', idx.to_s)) @@ -62,7 +68,13 @@ class Tk::BWidget::ButtonBox def insert(idx, keys={}, &b) win = window(tk_send('insert', tagid(idx), *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/combobox.rb b/ext/tk/lib/tkextlib/bwidget/combobox.rb index 31f71c3aaf..1c58a4ccb0 100644 --- a/ext/tk/lib/tkextlib/bwidget/combobox.rb +++ b/ext/tk/lib/tkextlib/bwidget/combobox.rb @@ -25,7 +25,13 @@ class Tk::BWidget::ComboBox def get_listbox(&b) win = window(tk_send_without_enc('getlistbox')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/dialog.rb b/ext/tk/lib/tkextlib/bwidget/dialog.rb index 2790d88d24..0ddee21d05 100644 --- a/ext/tk/lib/tkextlib/bwidget/dialog.rb +++ b/ext/tk/lib/tkextlib/bwidget/dialog.rb @@ -103,7 +103,7 @@ class Tk::BWidget::Dialog name = tagOrId[:name] return index(name) unless name.empty? end - if tagOrId.kind_of?(TkButton) + if tagOrId.kind_of?(Tk::Button) return index(tagOrId[:text]) end # index(tagOrId.to_s) @@ -112,19 +112,37 @@ class Tk::BWidget::Dialog def add(keys={}, &b) win = window(tk_send('add', *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_frame(&b) win = window(tk_send('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_buttonbox(&b) win = window(@path + '.bbox') - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/entry.rb b/ext/tk/lib/tkextlib/bwidget/entry.rb index aafb4aa7ff..a56890f4e3 100644 --- a/ext/tk/lib/tkextlib/bwidget/entry.rb +++ b/ext/tk/lib/tkextlib/bwidget/entry.rb @@ -9,7 +9,7 @@ require 'tkextlib/bwidget.rb' module Tk module BWidget - class Entry < TkEntry + class Entry < Tk::Entry end end end diff --git a/ext/tk/lib/tkextlib/bwidget/label.rb b/ext/tk/lib/tkextlib/bwidget/label.rb index ce10ecaf8b..88a504aa50 100644 --- a/ext/tk/lib/tkextlib/bwidget/label.rb +++ b/ext/tk/lib/tkextlib/bwidget/label.rb @@ -9,7 +9,7 @@ require 'tkextlib/bwidget.rb' module Tk module BWidget - class Label < TkLabel + class Label < Tk::Label end end end diff --git a/ext/tk/lib/tkextlib/bwidget/labelentry.rb b/ext/tk/lib/tkextlib/bwidget/labelentry.rb index 931feb9b48..95b40946a6 100644 --- a/ext/tk/lib/tkextlib/bwidget/labelentry.rb +++ b/ext/tk/lib/tkextlib/bwidget/labelentry.rb @@ -11,7 +11,7 @@ require 'tkextlib/bwidget/entry' module Tk module BWidget - class LabelEntry < TkEntry + class LabelEntry < Tk::Entry end end end diff --git a/ext/tk/lib/tkextlib/bwidget/labelframe.rb b/ext/tk/lib/tkextlib/bwidget/labelframe.rb index f7b267eebb..dc221806e4 100644 --- a/ext/tk/lib/tkextlib/bwidget/labelframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/labelframe.rb @@ -40,7 +40,13 @@ class Tk::BWidget::LabelFrame end def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end end diff --git a/ext/tk/lib/tkextlib/bwidget/listbox.rb b/ext/tk/lib/tkextlib/bwidget/listbox.rb index 1267500661..d8cd72fec2 100644 --- a/ext/tk/lib/tkextlib/bwidget/listbox.rb +++ b/ext/tk/lib/tkextlib/bwidget/listbox.rb @@ -211,14 +211,26 @@ class Tk::BWidget::ListBox::Item include TkTreatTagFont ListItem_TBL = TkCore::INTERP.create_table - ListItem_ID = ['bw:item'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ ListItem_TBL.clear } + (ListItem_ID = ['bw:item'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + ListItem_TBL.mutex.synchronize{ ListItem_TBL.clear } + } def self.id2obj(lbox, id) lpath = lbox.path - return id unless ListItem_TBL[lpath] - ListItem_TBL[lpath][id]? ListItem_TBL[lpath][id]: id + ListItem_TBL.mutex.synchronize{ + if ListItem_TBL[lpath] + ListItem_TBL[lpath][id]? ListItem_TBL[lpath][id]: id + else + id + end + } end def initialize(lbox, *args) @@ -250,13 +262,17 @@ class Tk::BWidget::ListBox::Item if keys.key?('itemname') @path = @id = keys.delete('itemname') else - @path = @id = ListItem_ID.join(TkCore::INTERP._ip_id_) - ListItem_ID[1].succ! + ListItem_ID.mutex.synchronize{ + @path = @id = ListItem_ID.join(TkCore::INTERP._ip_id_) + ListItem_ID[1].succ! + } end - ListItem_TBL[@id] = self - ListItem_TBL[@lpath] = {} unless ListItem_TBL[@lpath] - ListItem_TBL[@lpath][@id] = self + ListItem_TBL.mutex.synchronize{ + ListItem_TBL[@id] = self + ListItem_TBL[@lpath] = {} unless ListItem_TBL[@lpath] + ListItem_TBL[@lpath][@id] = self + } @listbox.insert(index, @id, keys) end diff --git a/ext/tk/lib/tkextlib/bwidget/mainframe.rb b/ext/tk/lib/tkextlib/bwidget/mainframe.rb index c54e878557..de66eaf81e 100644 --- a/ext/tk/lib/tkextlib/bwidget/mainframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/mainframe.rb @@ -41,37 +41,73 @@ class Tk::BWidget::MainFrame def add_indicator(keys={}, &b) win = window(tk_send('addindicator', *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def add_toolbar(&b) win = window(tk_send('addtoolbar')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_frame(&b) win = window(tk_send('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_indicator(idx, &b) win = window(tk_send('getindicator', idx)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_menu(menu_id, &b) win = window(tk_send('getmenu', menu_id)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end def get_toolbar(idx, &b) win = window(tk_send('gettoolbar', idx)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/messagedlg.rb b/ext/tk/lib/tkextlib/bwidget/messagedlg.rb index 9c946d0630..cc8a996f46 100644 --- a/ext/tk/lib/tkextlib/bwidget/messagedlg.rb +++ b/ext/tk/lib/tkextlib/bwidget/messagedlg.rb @@ -173,6 +173,9 @@ class Tk::BWidget::MessageDlg end def create - num_or_str(tk_call(self.class::TkCommandNames[0], @path, *hash_kv(@keys))) + # return the index of the pressed button, or nil if it is destroyed + ret = num_or_str(tk_call(self.class::TkCommandNames[0], + @path, *hash_kv(@keys))) + (ret < 0)? nil: ret end end diff --git a/ext/tk/lib/tkextlib/bwidget/notebook.rb b/ext/tk/lib/tkextlib/bwidget/notebook.rb index 5146d4915d..423943619c 100644 --- a/ext/tk/lib/tkextlib/bwidget/notebook.rb +++ b/ext/tk/lib/tkextlib/bwidget/notebook.rb @@ -89,7 +89,13 @@ class Tk::BWidget::NoteBook def add(page, &b) win = window(tk_send('add', tagid(page))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end @@ -105,7 +111,13 @@ class Tk::BWidget::NoteBook def get_frame(page, &b) win = window(tk_send('getframe', tagid(page))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end @@ -115,7 +127,13 @@ class Tk::BWidget::NoteBook def insert(index, page, keys={}, &b) win = window(tk_send('insert', index, tagid(page), *hash_kv(keys))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb b/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb index fc01284be6..fbc2c11255 100644 --- a/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb +++ b/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb @@ -26,7 +26,13 @@ class Tk::BWidget::PagesManager def add(page, &b) win = window(tk_send('add', tagid(page))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end @@ -42,7 +48,13 @@ class Tk::BWidget::PagesManager def get_frame(page, &b) win = window(tk_send('getframe', tagid(page))) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/panedwindow.rb b/ext/tk/lib/tkextlib/bwidget/panedwindow.rb index 19982c6095..4d979fd523 100644 --- a/ext/tk/lib/tkextlib/bwidget/panedwindow.rb +++ b/ext/tk/lib/tkextlib/bwidget/panedwindow.rb @@ -25,7 +25,13 @@ class Tk::BWidget::PanedWindow def get_frame(idx, &b) win = window(tk_send_without_enc('getframe', idx)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end end diff --git a/ext/tk/lib/tkextlib/bwidget/panelframe.rb b/ext/tk/lib/tkextlib/bwidget/panelframe.rb index 13f8817d74..84bae0768b 100644 --- a/ext/tk/lib/tkextlib/bwidget/panelframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/panelframe.rb @@ -36,7 +36,13 @@ class Tk::BWidget::PanelFrame def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/progressdlg.rb b/ext/tk/lib/tkextlib/bwidget/progressdlg.rb index fbf00f3b00..32600255d5 100644 --- a/ext/tk/lib/tkextlib/bwidget/progressdlg.rb +++ b/ext/tk/lib/tkextlib/bwidget/progressdlg.rb @@ -51,4 +51,8 @@ class Tk::BWidget::ProgressDlg def value= (val) @keys['variable'].value = val end + + def create + window(tk_call(self.class::TkCommandNames[0], @path, *hash_kv(@keys))) + end end diff --git a/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb b/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb index a3986681a5..010c960ec5 100644 --- a/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb @@ -23,7 +23,13 @@ class Tk::BWidget::ScrollableFrame def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb b/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb index e9e53235b7..3599fd8459 100644 --- a/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb +++ b/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb @@ -21,7 +21,13 @@ class Tk::BWidget::ScrolledWindow def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/selectcolor.rb b/ext/tk/lib/tkextlib/bwidget/selectcolor.rb index 742a84cd84..0f9014f8de 100644 --- a/ext/tk/lib/tkextlib/bwidget/selectcolor.rb +++ b/ext/tk/lib/tkextlib/bwidget/selectcolor.rb @@ -10,6 +10,11 @@ require 'tkextlib/bwidget/messagedlg' module Tk module BWidget class SelectColor < Tk::BWidget::MessageDlg + class Dialog < Tk::BWidget::SelectColor + end + class Menubutton < Tk::Menubutton + end + MenuButton = Menubutton end end end @@ -43,3 +48,26 @@ class Tk::BWidget::SelectColor tk_call('SelectColor::setcolor', idx, color) end end + +class Tk::BWidget::SelectColor::Dialog + def create_self(keys) + super(keys) + @keys['type'] = 'dialog' + end + + def create + @keys['type'] = 'dialog' # 'dialog' type returns color + tk_call(Tk::BWidget::SelectColor::TkCommandNames[0], + @path, *hash_kv(@keys)) + end +end + +class Tk::BWidget::SelectColor::Menubutton + def create_self(keys) + keys = {} unless keys + keys = _symbolkey2str(keys) + keys['type'] = 'menubutton' # 'toolbar' type returns widget path + window(tk_call(Tk::BWidget::SelectColor::TkCommandNames[0], + @path, *hash_kv(keys))) + end +end diff --git a/ext/tk/lib/tkextlib/bwidget/selectfont.rb b/ext/tk/lib/tkextlib/bwidget/selectfont.rb index 478787602a..e53eb3b5bc 100644 --- a/ext/tk/lib/tkextlib/bwidget/selectfont.rb +++ b/ext/tk/lib/tkextlib/bwidget/selectfont.rb @@ -66,7 +66,7 @@ class Tk::BWidget::SelectFont::Dialog end def create - @keys['type'] = 'dialog' + @keys['type'] = 'dialog' # 'dialog' type returns font name tk_call(Tk::BWidget::SelectFont::TkCommandNames[0], @path, *hash_kv(@keys)) end end @@ -79,7 +79,8 @@ class Tk::BWidget::SelectFont::Toolbar def create_self(keys) keys = {} unless keys keys = _symbolkey2str(keys) - keys['type'] = 'toolbar' - tk_call(Tk::BWidget::SelectFont::TkCommandNames[0], @path, *hash_kv(keys)) + keys['type'] = 'toolbar' # 'toolbar' type returns widget path + window(tk_call(Tk::BWidget::SelectFont::TkCommandNames[0], + @path, *hash_kv(keys))) end end diff --git a/ext/tk/lib/tkextlib/bwidget/spinbox.rb b/ext/tk/lib/tkextlib/bwidget/spinbox.rb index ca4c046e5c..48358baa5c 100644 --- a/ext/tk/lib/tkextlib/bwidget/spinbox.rb +++ b/ext/tk/lib/tkextlib/bwidget/spinbox.rb @@ -10,7 +10,7 @@ require 'tkextlib/bwidget/entry' module Tk module BWidget - class SpinBox < TkEntry + class SpinBox < Tk::Entry end end end diff --git a/ext/tk/lib/tkextlib/bwidget/statusbar.rb b/ext/tk/lib/tkextlib/bwidget/statusbar.rb index df16e4c0b7..39c678d37e 100644 --- a/ext/tk/lib/tkextlib/bwidget/statusbar.rb +++ b/ext/tk/lib/tkextlib/bwidget/statusbar.rb @@ -36,7 +36,13 @@ class Tk::BWidget::StatusBar def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/bwidget/titleframe.rb b/ext/tk/lib/tkextlib/bwidget/titleframe.rb index f519490430..68534e66e9 100644 --- a/ext/tk/lib/tkextlib/bwidget/titleframe.rb +++ b/ext/tk/lib/tkextlib/bwidget/titleframe.rb @@ -21,7 +21,13 @@ class Tk::BWidget::TitleFrame def get_frame(&b) win = window(tk_send_without_enc('getframe')) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end end diff --git a/ext/tk/lib/tkextlib/bwidget/tree.rb b/ext/tk/lib/tkextlib/bwidget/tree.rb index e7178debe2..7a46db575e 100644 --- a/ext/tk/lib/tkextlib/bwidget/tree.rb +++ b/ext/tk/lib/tkextlib/bwidget/tree.rb @@ -263,14 +263,26 @@ class Tk::BWidget::Tree::Node include TkTreatTagFont TreeNode_TBL = TkCore::INTERP.create_table - TreeNode_ID = ['bw:node'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ TreeNode_TBL.clear } + (TreeNode_ID = ['bw:node'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + TreeNode_TBL.mutex.synchronize{ TreeNode_TBL.clear } + } def self.id2obj(tree, id) tpath = tree.path - return id unless TreeNode_TBL[tpath] - TreeNode_TBL[tpath][id]? TreeNode_TBL[tpath][id]: id + TreeNode_TBL.mutex.synchronize{ + if TreeNode_TBL[tpath] + TreeNode_TBL[tpath][id]? TreeNode_TBL[tpath][id]: id + else + id + end + } end def initialize(tree, *args) @@ -311,13 +323,17 @@ class Tk::BWidget::Tree::Node if keys.key?('nodename') @path = @id = keys.delete('nodename') else - @path = @id = TreeNode_ID.join(TkCore::INTERP._ip_id_) - TreeNode_ID[1].succ! + TreeNode_ID.mutex.synchronize{ + @path = @id = TreeNode_ID.join(TkCore::INTERP._ip_id_) + TreeNode_ID[1].succ! + } end - TreeNode_TBL[@id] = self - TreeNode_TBL[@tpath] = {} unless TreeNode_TBL[@tpath] - TreeNode_TBL[@tpath][@id] = self + TreeNode_TBL.mutex.synchronize{ + TreeNode_TBL[@id] = self + TreeNode_TBL[@tpath] = {} unless TreeNode_TBL[@tpath] + TreeNode_TBL[@tpath][@id] = self + } @tree.insert(index, parent, @id, keys) end diff --git a/ext/tk/lib/tkextlib/bwidget/widget.rb b/ext/tk/lib/tkextlib/bwidget/widget.rb index 568e503a8b..34e51308a5 100644 --- a/ext/tk/lib/tkextlib/bwidget/widget.rb +++ b/ext/tk/lib/tkextlib/bwidget/widget.rb @@ -43,7 +43,13 @@ module Tk::BWidget::Widget def self.create(klass, path, rename=None, &b) win = window(tk_call('Widget::create', klass, path, rename)) - win.instance_eval(&b) if b + if b + if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!! + win.instance_exec(self, &b) + else + win.instance_eval(&b) + end + end win end diff --git a/ext/tk/lib/tkextlib/itcl/incr_tcl.rb b/ext/tk/lib/tkextlib/itcl/incr_tcl.rb index 07abf3a7bf..2b75d62eb9 100644 --- a/ext/tk/lib/tkextlib/itcl/incr_tcl.rb +++ b/ext/tk/lib/tkextlib/itcl/incr_tcl.rb @@ -40,16 +40,22 @@ module Tk class ItclObject < TkObject ITCL_CLASSNAME = ''.freeze - ITCL_OBJ_ID = ['itclobj'.freeze, '00000'.taint].freeze + (ITCL_OBJ_ID = ['itclobj'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } ITCL_OBJ_TBL = {}.taint def initialize(*args) if (@klass = self.class::ITCL_CLASSNAME).empty? fail RuntimeError, 'unknown itcl class (abstract class?)' end - @id = Tk::Itcl::ItclObject::TCL_OBJ_ID.join(TkCore::INTERP._ip_id_) + Tk::Itcl::ItclObject::ITCL_OBJ_ID.mutex.synchronize{ + @id = Tk::Itcl::ItclObject::TCL_OBJ_ID.join(TkCore::INTERP._ip_id_) + Tk::Itcl::ItclObject::ITCL_OBJ_ID[1].succ! + } @path = @id - Tk::Itcl::ItclObject::ITCL_OBJ_ID[1].succ! end def self.call_proc(name, *args) diff --git a/ext/tk/lib/tkextlib/itk/incr_tk.rb b/ext/tk/lib/tkextlib/itk/incr_tk.rb index 0626536e36..e06deb552c 100644 --- a/ext/tk/lib/tkextlib/itk/incr_tk.rb +++ b/ext/tk/lib/tkextlib/itk/incr_tk.rb @@ -145,9 +145,16 @@ module Tk private :__config_cmd ComponentID_TBL = TkCore::INTERP.create_table - Itk_Component_ID = ['itk:component'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ ComponentID_TBL.clear } + (Itk_Component_ID = ['itk:component'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + ComponentID_TBL.mutex.synchronize{ ComponentID_TBL.clear } + } def self.id2obj(master, id) if master.kind_of?(TkObject) @@ -155,8 +162,13 @@ module Tk else master = master.to_s end - return id unless ComponentID_TBL.key?(master) - (ComponentID_TBL.key?(id))? ComponentID_TBL[master][id]: id + ComponentID_TBL.mutex.synchronize{ + if ComponentID_TBL.key?(master) + (ComponentID_TBL[master].key?(id))? ComponentID_TBL[master][id]: id + else + id + end + } end def self.new(master, component=nil) @@ -171,17 +183,21 @@ module Tk elsif component component = component.to_s else - component = Itk_Component_ID.join(TkCore::INTERP._ip_id_) - Itk_Component_ID[1].succ! + Itk_Component_ID.mutex.synchronize{ + component = Itk_Component_ID.join(TkCore::INTERP._ip_id_) + Itk_Component_ID[1].succ! + } end - if ComponentID_TBL.key?(master) - if ComponentID_TBL[master].key?(component) - return ComponentID_TBL[master][component] + ComponentID_TBL.mutex.synchronize{ + if ComponentID_TBL.key?(master) + if ComponentID_TBL[master].key?(component) + return ComponentID_TBL[master][component] + end + else + ComponentID_TBL[master] = {} end - else - ComponentID_TBL[master] = {} - end + } super(master, component) end @@ -190,7 +206,9 @@ module Tk @master = master @component = component - ComponentID_TBL[@master][@component] = self + ComponentID_TBL.mutex.synchronize{ + ComponentID_TBL[@master][@component] = self + } begin @widget = window(tk_call(@master, 'component', @component)) diff --git a/ext/tk/lib/tkextlib/iwidgets/calendar.rb b/ext/tk/lib/tkextlib/iwidgets/calendar.rb index 0152f8593a..236ca96f00 100644 --- a/ext/tk/lib/tkextlib/iwidgets/calendar.rb +++ b/ext/tk/lib/tkextlib/iwidgets/calendar.rb @@ -45,6 +45,23 @@ class Tk::Iwidgets::Calendar class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [?d, ?s, :date], nil ] PROC_TBL = [ [?s, TkComm.method(:string) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) diff --git a/ext/tk/lib/tkextlib/iwidgets/checkbox.rb b/ext/tk/lib/tkextlib/iwidgets/checkbox.rb index 46ca389db2..7d2b41f806 100644 --- a/ext/tk/lib/tkextlib/iwidgets/checkbox.rb +++ b/ext/tk/lib/tkextlib/iwidgets/checkbox.rb @@ -85,12 +85,24 @@ class Tk::Iwidgets::Checkbox self end - def get(idx) - simplelist(tk_call(@path, 'get', index(idx))).collect{|id| + def get_tags + simplelist(tk_call_without_enc(@path, 'get')) + end + + def get_objs + simplelist(tk_call_without_enc(@path, 'get')).collect{|id| Tk::Itk::Component.id2obj(self, id) } end + def get(idx=nil) + if idx + bool(tk_call_without_enc(@path, 'get', index(idx))) + else + get_tags + end + end + def index(idx) number(tk_call(@path, 'index', tagid(idx))) end diff --git a/ext/tk/lib/tkextlib/iwidgets/entryfield.rb b/ext/tk/lib/tkextlib/iwidgets/entryfield.rb index 6aa933ce06..1f9effb46e 100644 --- a/ext/tk/lib/tkextlib/iwidgets/entryfield.rb +++ b/ext/tk/lib/tkextlib/iwidgets/entryfield.rb @@ -42,6 +42,23 @@ class Tk::Iwidgets::Entryfield [ ?w, TkComm.method(:window) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); end diff --git a/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb b/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb index 4cc6aeecbd..4e7d8f8579 100644 --- a/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb +++ b/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb @@ -30,6 +30,23 @@ class Tk::Iwidgets::Hierarchy class ValidateArgs < TkUtil::CallbackSubst KEY_TBL = [ [?n, ?s, :node], nil ] PROC_TBL = [ [?s, TkComm.method(:string) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -57,6 +74,22 @@ class Tk::Iwidgets::Hierarchy nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -78,6 +111,23 @@ class Tk::Iwidgets::Hierarchy nil ] PROC_TBL = [ [ ?s, TkComm.method(:string) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -207,7 +257,7 @@ class Tk::Iwidgets::Hierarchy self end - # based on TkText widget + # based on Tk::Text widget def bbox(index) list(tk_send_without_enc('bbox', _get_eval_enc_str(index))) diff --git a/ext/tk/lib/tkextlib/iwidgets/notebook.rb b/ext/tk/lib/tkextlib/iwidgets/notebook.rb index 0f9d713ea1..268452afec 100644 --- a/ext/tk/lib/tkextlib/iwidgets/notebook.rb +++ b/ext/tk/lib/tkextlib/iwidgets/notebook.rb @@ -146,7 +146,12 @@ class Tk::Iwidgets::Notebook def view(*idxs) if idxs.size == 0 - window(tk_send_without_enc('view')) + idx = num_or_str(tk_send_without_enc('view')) + if idx.kind_of?(Fixnum) && idx < 0 + nil + else + idx + end else tk_send_without_enc('view', *idxs) self @@ -160,8 +165,8 @@ class Tk::Iwidgets::Notebook end alias xview_moveto view_moveto alias yview_moveto view_moveto - def view_scroll(*idxs) - view('scroll', *idxs) + def view_scroll(index, what='pages') + view('scroll', index, what) end alias xview_scroll view_scroll alias yview_scroll view_scroll diff --git a/ext/tk/lib/tkextlib/iwidgets/radiobox.rb b/ext/tk/lib/tkextlib/iwidgets/radiobox.rb index 1a2821bd6a..cfcbca1aad 100644 --- a/ext/tk/lib/tkextlib/iwidgets/radiobox.rb +++ b/ext/tk/lib/tkextlib/iwidgets/radiobox.rb @@ -85,10 +85,13 @@ class Tk::Iwidgets::Radiobox self end - def get(idx) - simplelist(tk_call(@path, 'get', index(idx))).collect{|id| - Tk::Itk::Component.id2obj(self, id) - } + def get_tag + ((tag = tk_call_without_enc(@path, 'get')).empty?)? nil: tag + end + alias get get_tag + + def get_obj + (tag = get_tag)? Tk::Itk::Component.id2obj(self, tag): nil end def index(idx) diff --git a/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb b/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb index 407c8f2aad..b07602e340 100644 --- a/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb +++ b/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb @@ -171,10 +171,16 @@ class Tk::Iwidgets::Scrolledcanvas end def delete(*args) - if TkcItem::CItemID_TBL[self.path] + tbl = nil + TkcItem::CItemID_TBL.mutex.synchronize{ + tbl = TkcItem::CItemID_TBL[self.path] + } + if tbl find('withtag', *args).each{|item| if item.kind_of?(TkcItem) - TkcItem::CItemID_TBL[self.path].delete(item.id) + TkcItem::CItemID_TBL.mutex.synchronize{ + tbl.delete(item.id) + } end } end diff --git a/ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb b/ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb index fdafc8dc7f..2887b60815 100644 --- a/ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb +++ b/ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb @@ -322,6 +322,11 @@ class Tk::Iwidgets::Scrolledtext def _ktext_length(txt) + if TkCore::WITH_ENCODING ### Ruby 1.9 !!!!!!!!!!!!! + return txt.length + end + ########################### + if $KCODE !~ /n/i return txt.gsub(/[^\Wa-zA-Z_\d]/, ' ').length end diff --git a/ext/tk/lib/tkextlib/iwidgets/selectionbox.rb b/ext/tk/lib/tkextlib/iwidgets/selectionbox.rb index bb81fcca5e..bf9b5ec30a 100644 --- a/ext/tk/lib/tkextlib/iwidgets/selectionbox.rb +++ b/ext/tk/lib/tkextlib/iwidgets/selectionbox.rb @@ -59,7 +59,7 @@ class Tk::Iwidgets::Selectionbox self end - # based on TkListbox ( and TkTextWin ) + # based on Tk::Listbox ( and TkTextWin ) def curselection list(tk_send_without_enc('curselection')) end diff --git a/ext/tk/lib/tkextlib/iwidgets/selectiondialog.rb b/ext/tk/lib/tkextlib/iwidgets/selectiondialog.rb index ab790e97a6..f772ecf8c2 100644 --- a/ext/tk/lib/tkextlib/iwidgets/selectiondialog.rb +++ b/ext/tk/lib/tkextlib/iwidgets/selectiondialog.rb @@ -49,7 +49,7 @@ class Tk::Iwidgets::Selectiondialog self end - # based on TkListbox ( and TkTextWin ) + # based on Tk::Listbox ( and TkTextWin ) def curselection list(tk_send_without_enc('curselection')) end diff --git a/ext/tk/lib/tkextlib/iwidgets/spinner.rb b/ext/tk/lib/tkextlib/iwidgets/spinner.rb index 174b9bd506..126cfe7c95 100644 --- a/ext/tk/lib/tkextlib/iwidgets/spinner.rb +++ b/ext/tk/lib/tkextlib/iwidgets/spinner.rb @@ -37,6 +37,23 @@ class Tk::Iwidgets::Spinner [ ?w, TkComm.method(:window) ], nil ] + + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); end diff --git a/ext/tk/lib/tkextlib/iwidgets/tabnotebook.rb b/ext/tk/lib/tkextlib/iwidgets/tabnotebook.rb index 0d9715f87b..382604102e 100644 --- a/ext/tk/lib/tkextlib/iwidgets/tabnotebook.rb +++ b/ext/tk/lib/tkextlib/iwidgets/tabnotebook.rb @@ -116,6 +116,11 @@ class Tk::Iwidgets::Tabnotebook self end + def show_tab(idx) + @tabset.show_tab(idx) + self + end + def scrollcommand(cmd=Proc.new) configure_cmd 'scrollcommand', cmd self @@ -147,7 +152,12 @@ class Tk::Iwidgets::Tabnotebook def view(*index) if index.size == 0 - window(tk_send_without_enc('view')) + idx = num_or_str(tk_send_without_enc('view')) + if idx.kind_of?(Fixnum) && idx < 0 + nil + else + idx + end else tk_send_without_enc('view', *index) self @@ -161,8 +171,8 @@ class Tk::Iwidgets::Tabnotebook end alias xview_moveto view_moveto alias yview_moveto view_moveto - def view_scroll(*index) - view('scroll', *index) + def view_scroll(index, what='pages') + view('scroll', index, what) end alias xview_scroll view_scroll alias yview_scroll view_scroll diff --git a/ext/tk/lib/tkextlib/iwidgets/tabset.rb b/ext/tk/lib/tkextlib/iwidgets/tabset.rb index 54e56d0514..618260e8e3 100644 --- a/ext/tk/lib/tkextlib/iwidgets/tabset.rb +++ b/ext/tk/lib/tkextlib/iwidgets/tabset.rb @@ -96,4 +96,48 @@ class Tk::Iwidgets::Tabset tk_call(@path, 'select', index(idx)) self end + + def show_tab(idx) + if index(idx) == 0 + self.start = 0 + return + end + + reutrn unless @canvas ||= self.winfo_children[0] + + delta = 1 if (delta = cget(:gap)) == 'overlap' || + (delta = self.winfo_pixels(delta) + 1) <= 0 + + case cget(:tabpos) + when 's', 'n' + if (head = tabcget(idx, :left)) < 0 + self.start -= head + return + end + tabs_size = @canvas.winfo_width + tab_start, tab_end = @canvas . + find_overlapping(head, 0, head + delta, @canvas.winfo_height) . + find_all{|id| @canvas.itemtype(id) == TkcPolygon} . + map!{|id| bbox = @canvas.bbox(id); [bbox[0], bbox[2]]} . max + + when 'e', 'w' + if (head = tabcget(idx, :top)) < 0 + self.start -= head + return + end + tabs_size = @canvas.winfo_height + tab_start, tab_end = @canvas . + find_overlapping(0, head, @canvas.winfo_width, head + delta) . + find_all{|id| @canvas.itemtype(id) == TkcPolygon} . + map!{|id| bbox = @canvas.bbox(id); [bbox[1], bbox[3]]} . max + end + + if (size = tab_end - tab_start + 1) > tabs_size + self.start -= tab_start + elsif head + size > tabs_size + self.start -= head + size - tabs_size + end + + self + end end diff --git a/ext/tk/lib/tkextlib/tcllib/autoscroll.rb b/ext/tk/lib/tkextlib/tcllib/autoscroll.rb index 6940a9174c..7db3c2e2b7 100644 --- a/ext/tk/lib/tkextlib/tcllib/autoscroll.rb +++ b/ext/tk/lib/tkextlib/tcllib/autoscroll.rb @@ -108,7 +108,7 @@ module Tk end end -class TkScrollbar +class Tk::Scrollbar def autoscroll # Arranges for the already existing scrollbar to be mapped # and unmapped as needed. diff --git a/ext/tk/lib/tkextlib/tcllib/ctext.rb b/ext/tk/lib/tkextlib/tcllib/ctext.rb index 70a45dd8e7..9014037f3d 100644 --- a/ext/tk/lib/tkextlib/tcllib/ctext.rb +++ b/ext/tk/lib/tkextlib/tcllib/ctext.rb @@ -15,7 +15,7 @@ TkPackage.require('ctext') module Tk module Tcllib - class CText < TkText + class CText < Tk::Text PACKAGE_NAME = 'ctext'.freeze def self.package_name PACKAGE_NAME diff --git a/ext/tk/lib/tkextlib/tcllib/datefield.rb b/ext/tk/lib/tkextlib/tcllib/datefield.rb index bd84488101..2244dd7a9a 100644 --- a/ext/tk/lib/tkextlib/tcllib/datefield.rb +++ b/ext/tk/lib/tkextlib/tcllib/datefield.rb @@ -24,7 +24,7 @@ TkPackage.require('datefield') module Tk module Tcllib - class Datefield < TkEntry + class Datefield < Tk::Entry PACKAGE_NAME = 'datefield'.freeze def self.package_name PACKAGE_NAME diff --git a/ext/tk/lib/tkextlib/tcllib/ico.rb b/ext/tk/lib/tkextlib/tcllib/ico.rb index 3beeb11a4d..8c92926a4c 100644 --- a/ext/tk/lib/tkextlib/tcllib/ico.rb +++ b/ext/tk/lib/tkextlib/tcllib/ico.rb @@ -94,8 +94,10 @@ class Tk::Tcllib::ICO if keys.key?('name') @path = keys['name'].to_s else - @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_) - Tk_Image_ID[1].succ! + Tk_Image_ID.mutex.synchronize{ + @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_) + Tk_Image_ID[1].succ! + } end tk_call_without_enc('::ico::getIcon', file, index, '-name', @path, '-format', 'image', *hash_kv(keys, true)) diff --git a/ext/tk/lib/tkextlib/tcllib/ip_entry.rb b/ext/tk/lib/tkextlib/tcllib/ip_entry.rb index 8c9e0bd683..c4b8240c04 100644 --- a/ext/tk/lib/tkextlib/tcllib/ip_entry.rb +++ b/ext/tk/lib/tkextlib/tcllib/ip_entry.rb @@ -18,7 +18,7 @@ TkPackage.require('ipentry') module Tk module Tcllib - class IP_Entry < TkEntry + class IP_Entry < Tk::Entry PACKAGE_NAME = 'ipentry'.freeze def self.package_name PACKAGE_NAME diff --git a/ext/tk/lib/tkextlib/tcllib/plotchart.rb b/ext/tk/lib/tkextlib/tcllib/plotchart.rb index f5f344ceb3..06ab20f3e6 100644 --- a/ext/tk/lib/tkextlib/tcllib/plotchart.rb +++ b/ext/tk/lib/tkextlib/tcllib/plotchart.rb @@ -225,7 +225,7 @@ module Tk::Tcllib::Plotchart end ############################ - class XYPlot < TkCanvas + class XYPlot < Tk::Canvas include ChartMethod TkCommandNames = [ @@ -247,7 +247,7 @@ module Tk::Tcllib::Plotchart @xaxis = args.shift @yaxis = args.shift - if parent.kind_of?(TkCanvas) + if parent.kind_of?(Tk::Canvas) @path = parent.path else super(parent, *args) # create canvas widget @@ -265,7 +265,9 @@ module Tk::Tcllib::Plotchart private :_create_chart def __destroy_hook__ - Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{ + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + } end def plot(series, x, y) @@ -337,7 +339,7 @@ module Tk::Tcllib::Plotchart end ############################ - class PolarPlot < TkCanvas + class PolarPlot < Tk::Canvas include ChartMethod TkCommandNames = [ @@ -356,7 +358,7 @@ module Tk::Tcllib::Plotchart @radius_data = args.shift - if parent.kind_of?(TkCanvas) + if parent.kind_of?(Tk::Canvas) @path = parent.path else super(parent, *args) # create canvas widget @@ -374,7 +376,9 @@ module Tk::Tcllib::Plotchart private :_create_chart def __destroy_hook__ - Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{ + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + } end def plot(series, radius, angle) @@ -395,7 +399,7 @@ module Tk::Tcllib::Plotchart Polarplot = PolarPlot ############################ - class IsometricPlot < TkCanvas + class IsometricPlot < Tk::Canvas include ChartMethod TkCommandNames = [ @@ -430,7 +434,7 @@ module Tk::Tcllib::Plotchart @stepsize = args.shift end - if parent.kind_of?(TkCanvas) + if parent.kind_of?(Tk::Canvas) @path = parent.path else super(parent, *args) # create canvas widget @@ -475,7 +479,7 @@ module Tk::Tcllib::Plotchart Isometricplot = IsometricPlot ############################ - class Plot3D < TkCanvas + class Plot3D < Tk::Canvas include ChartMethod TkCommandNames = [ @@ -500,7 +504,7 @@ module Tk::Tcllib::Plotchart @yaxis = args.shift @zaxis = args.shift - if parent.kind_of?(TkCanvas) + if parent.kind_of?(Tk::Canvas) @path = parent.path else super(parent, *args) # create canvas widget @@ -557,7 +561,7 @@ module Tk::Tcllib::Plotchart end ############################ - class Piechart < TkCanvas + class Piechart < Tk::Canvas include ChartMethod TkCommandNames = [ @@ -566,7 +570,7 @@ module Tk::Tcllib::Plotchart ].freeze def initialize(*args) # args := ([parent] [, keys]) - if args[0].kind_of?(TkCanvas) + if args[0].kind_of?(Tk::Canvas) parent = args.shift @path = parent.path else @@ -588,7 +592,7 @@ module Tk::Tcllib::Plotchart end ############################ - class Barchart < TkCanvas + class Barchart < Tk::Canvas include ChartMethod TkCommandNames = [ @@ -626,7 +630,7 @@ module Tk::Tcllib::Plotchart @series_size = args.shift end - if parent.kind_of?(TkCanvas) + if parent.kind_of?(Tk::Canvas) @path = parent.path else super(parent, *args) # create canvas widget @@ -645,7 +649,9 @@ module Tk::Tcllib::Plotchart private :_create_chart def __destroy_hook__ - Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{ + Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path) + } end def plot(series, dat, col=None) @@ -672,7 +678,7 @@ module Tk::Tcllib::Plotchart end ############################ - class Timechart < TkCanvas + class Timechart < Tk::Canvas include ChartMethod TkCommandNames = [ @@ -699,7 +705,7 @@ module Tk::Tcllib::Plotchart @time_end = args.shift @items = args.shift - if parent.kind_of?(TkCanvas) + if parent.kind_of?(Tk::Canvas) @path = parent.path else super(parent, *args) # create canvas widget @@ -733,7 +739,7 @@ module Tk::Tcllib::Plotchart end ############################ - class Gnattchart < TkCanvas + class Gnattchart < Tk::Canvas include ChartMethod TkCommandNames = [ @@ -772,7 +778,7 @@ module Tk::Tcllib::Plotchart @text_width = None end - if parent.kind_of?(TkCanvas) + if parent.kind_of?(Tk::Canvas) @path = parent.path else super(parent, *args) # create canvas widget @@ -834,23 +840,38 @@ module Tk::Tcllib::Plotchart ############################ class PlotSeries < TkObject SeriesID_TBL = TkCore::INTERP.create_table - Series_ID = ['series'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ SeriesID_TBL.clear } + + (Series_ID = ['series'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + TkCore::INTERP.init_ip_env{ + SeriesID_TBL.mutex.synchronize{ SeriesID_TBL.clear } + } def self.id2obj(chart, id) path = chart.path - return id unless SeriesID_TBL[path] - SeriesID_TBL[path][id]? SeriesID_TBL[path][id]: id + SeriesID_TBL.mutex.synchronize{ + if SeriesID_TBL[path] + SeriesID_TBL[path][id]? SeriesID_TBL[path][id]: id + else + id + end + } end def initialize(chart, keys=nil) @parent = @chart_obj = chart @ppath = @chart_obj.path - @path = @series = @id = Series_ID.join(TkCore::INTERP._ip_id_) - # SeriesID_TBL[@id] = self - SeriesID_TBL[@ppath] = {} unless SeriesID_TBL[@ppath] - SeriesID_TBL[@ppath][@id] = self - Series_ID[1].succ! + Series_ID.mutex.synchronize{ + @path = @series = @id = Series_ID.join(TkCore::INTERP._ip_id_) + Series_ID[1].succ! + } + SeriesID_TBL.mutex.synchronize{ + SeriesID_TBL[@ppath] ||= {} + SeriesID_TBL[@ppath][@id] = self + } dataconfig(keys) if keys.kind_of?(Hash) end diff --git a/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb b/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb index 92dde65ce7..b366e0198b 100644 --- a/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb +++ b/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb @@ -125,7 +125,9 @@ module Tk::Tcllib::Tkpiechart def delete tk_call_without_enc('::stooop::delete', @tag_key) - CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + CItemID_TBL.mutex.synchronize{ + CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + } self end @@ -184,8 +186,10 @@ module Tk::Tcllib::Tkpiechart @id = "slices(#{@tag_key})" @tag = TkcNamedTag.new(@pie.canvas, @id) - CItemID_TBL[@path] = {} unless CItemID_TBL[@path] - CItemID_TBL[@path][@id] = self + CItemID_TBL.mutex.synchronize{ + CItemID_TBL[@path] = {} unless CItemID_TBL[@path] + CItemID_TBL[@path][@id] = self + } end def tag_key @@ -200,7 +204,9 @@ module Tk::Tcllib::Tkpiechart def delete tk_call_without_enc('pie::deleteSlice', @pie.tag_key, @tag_key) - CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + CItemID_TBL.mutex.synchronize{ + CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + } @pie._delete_slice(self) self end diff --git a/ext/tk/lib/tkextlib/tile.rb b/ext/tk/lib/tkextlib/tile.rb index acc7bebe4e..02473d57a1 100644 --- a/ext/tk/lib/tkextlib/tile.rb +++ b/ext/tk/lib/tkextlib/tile.rb @@ -4,6 +4,7 @@ # require 'tk' +require 'tk/ttk_selector' # call setup script for general 'tkextlib' libraries require 'tkextlib/setup.rb' @@ -15,33 +16,66 @@ require 'tkextlib/tile/setup.rb' # TkPackage.require('tile', '0.4') # TkPackage.require('tile', '0.6') # TkPackage.require('tile', '0.7') -verstr = TkPackage.require('tile') +if Tk::TK_MAJOR_VERSION > 8 || + (Tk::TK_MAJOR_VERSION == 8 && Tk::TK_MINOR_VERSION >= 5) + TkPackage.require('tile') # for compatibility (version check of 'tile') + verstr = TkPackage.require('Ttk') +else + verstr = TkPackage.require('tile') +end + ver = verstr.split('.') -if ver[0].to_i == 0 && ver[1].to_i <= 4 - # version 0.4 or former - module Tk - module Tile - USE_TILE_NAMESPACE = true - USE_TTK_NAMESPACE = false - TILE_SPEC_VERSION_ID = 0 +if ver[0].to_i == 0 + # Tile extension package + if ver[1].to_i <= 4 + # version 0.4 or former + module Tk + module Tile + USE_TILE_NAMESPACE = true + USE_TTK_NAMESPACE = false + TILE_SPEC_VERSION_ID = 0 + end end - end -elsif ver[0].to_i == 0 && ver[1].to_i <= 6 - # version 0.5 -- version 0.6 - module Tk - module Tile - USE_TILE_NAMESPACE = true - USE_TTK_NAMESPACE = true - TILE_SPEC_VERSION_ID = 5 + elsif ver[1].to_i <= 6 + # version 0.5 -- version 0.6 + module Tk + module Tile + USE_TILE_NAMESPACE = true + USE_TTK_NAMESPACE = true + TILE_SPEC_VERSION_ID = 5 + end + end + elsif ver[1].to_i <= 7 + module Tk + module Tile + USE_TILE_NAMESPACE = false + USE_TTK_NAMESPACE = true + TILE_SPEC_VERSION_ID = 7 + end + end + else + # version 0.8 or later + module Tk + module Tile + USE_TILE_NAMESPACE = false + USE_TTK_NAMESPACE = true + TILE_SPEC_VERSION_ID = 8 + end end end + + module Tk::Tile + PACKAGE_NAME = 'tile'.freeze + end else - # version 0.7 or later + # Ttk package merged Tcl/Tk core (Tcl/Tk 8.5+) module Tk module Tile USE_TILE_NAMESPACE = false USE_TTK_NAMESPACE = true - TILE_SPEC_VERSION_ID = 7 + TILE_SPEC_VERSION_ID = 8 + + PACKAGE_NAME = 'Ttk'.freeze end end end @@ -51,30 +85,110 @@ module Tk module Tile TkComm::TkExtlibAutoloadModule.unshift(self) - PACKAGE_NAME = 'tile'.freeze def self.package_name PACKAGE_NAME end def self.package_version begin - TkPackage.require('tile') + TkPackage.require(PACKAGE_NAME) rescue '' end end def self.__Import_Tile_Widgets__! + warn 'Warning: "Tk::Tile::__Import_Tile_Widgets__!" is obsolete.' << + ' To control default widget set, use "Tk.default_widget_set = :Ttk"' Tk.tk_call('namespace', 'import', '-force', 'ttk::*') end - def self.load_images(imgdir, pat=TkComm::None) - images = Hash[*TkComm.simplelist(Tk.tk_call('::tile::LoadImages', - imgdir, pat))] - images.keys.each{|k| - images[k] = TkPhotoImage.new(:imagename=>images[k], - :without_creating=>true) + def self.__define_LoadImages_proc_for_compatibility__! + # Ttk 8.5 (Tile 0.8) lost 'LoadImages' utility procedure. + # So, some old scripts doen't work, because those scripts use the + # procedure to define local styles. + # Of course, rewriting such Tcl/Tk scripts isn't difficult for + # Tcl/Tk users. However, it may be troublesome for Ruby/Tk users + # who use such Tcl/Tk scripts as it is. + # This method may help Ruby/Tk users who don't want to modify old + # Tcl/Tk scripts for the latest version of Ttk (Tile) extension. + # This method defines a comaptible 'LoadImages' procedure on the + # Tcl/Tk interpreter working under Ruby/Tk. + # Please give attention to use this method. It may conflict with + # some definitions on Tcl/Tk scripts. + klass_name = self.name + proc_name = 'LoadImages' + if Tk::Tile::USE_TTK_NAMESPACE + ns_list = ['::tile'] + if Tk.info(:commands, "::ttk::#{proc_name}").empty? + ns_list << '::ttk' + end + else # Tk::Tile::USE_TILE_NAMESPACE + ns_list = ['::ttk'] + if Tk.info(:commands, "::tile::#{proc_name}").empty? + ns_list << '::tile' + end + end + + ns_list.each{|ns| + cmd = "#{ns}::#{proc_name}" + unless Tk.info(:commands, cmd).empty? + fail RuntimeError, "can't define '#{cmd}' command (already exist)" + end + TkNamespace.eval(ns){ + TkCore::INTERP.add_tk_procs(proc_name, 'imgdir {patterns {*.gif}}', + <<-'EOS') + foreach pattern $patterns { + foreach file [glob -directory $imgdir $pattern] { + set img [file tail [file rootname $file]] + if {![info exists images($img)]} { + set images($img) [image create photo -file $file] + } + } + } + return [array get images] + EOS + } } + end + + def self.load_images(imgdir, pat=nil) + if Tk::Tile::TILE_SPEC_VERSION_ID < 8 + if Tk::Tile::USE_TTK_NAMESPACE + cmd = '::ttk::LoadImages' + else # Tk::Tile::USE_TILE_NAMESPACE + cmd = '::tile::LoadImages' + end + pat ||= TkComm::None + images = Hash[*TkComm.simplelist(Tk.tk_call(cmd, imgdir, pat))] + images.keys.each{|k| + images[k] = TkPhotoImage.new(:imagename=>images[k], + :without_creating=>true) + } + else ## TILE_SPEC_VERSION_ID >= 8 + pat ||= '*.gif' + if pat.kind_of?(Array) + pat_list = pat + else + pat_list = [ pat ] + end + Dir.chdir(imgdir){ + pat_list.each{|pat| + Dir.glob(pat).each{|f| + img = File.basename(f, '.*') + unless TkComm.bool(Tk.info('exists', "images(#{img})")) + Tk.tk_call('set', "images(#{img})", + Tk.tk_call('image', 'create', 'photo', '-file', f)) + end + } + } + } + images = Hash[*TkComm.simplelist(Tk.tk_call('array', 'get', 'images'))] + images.keys.each{|k| + images[k] = TkPhotoImage.new(:imagename=>images[k], + :without_creating=>true) + } + end images end @@ -84,11 +198,20 @@ module Tk end module KeyNav - def self.enableMnemonics(w) - Tk.tk_call('::keynav::enableMnemonics', w) - end - def self.defaultButton(w) - Tk.tk_call('::keynav::defaultButton', w) + if Tk::Tile::TILE_SPEC_VERSION_ID < 8 + def self.enableMnemonics(w) + Tk.tk_call('::keynav::enableMnemonics', w) + end + def self.defaultButton(w) + Tk.tk_call('::keynav::defaultButton', w) + end + else # dummy + def self.enableMnemonics(w) + "" + end + def self.defaultButton(w) + "" + end end end @@ -103,6 +226,12 @@ module Tk Menu = 'TkMenuFont' SmallCaption = 'TkSmallCaptionFont' Icon = 'TkIconFont' + + TkFont::SYSTEM_FONT_NAMES.add [ + 'TkDefaultFont', 'TkTextFont', 'TkHeadingFont', + 'TkCaptionFont', 'TkTooltipFont', 'TkFixedFont', + 'TkMenuFont', 'TkSmallCaptionFont', 'TkIconFont' + ] end module ParseStyleLayout @@ -141,7 +270,7 @@ module Tk end private :__val2ruby_optkeys - def instate(state, script=nil, &b) + def ttk_instate(state, script=nil, &b) if script tk_send('instate', state, script) elsif b @@ -150,19 +279,30 @@ module Tk bool(tk_send('instate', state)) end end + alias tile_instate ttk_instate - def state(state=nil) + def ttk_state(state=nil) if state tk_send('state', state) else list(tk_send('state')) end end + alias tile_state ttk_state - def identify(x, y) + def ttk_identify(x, y) ret = tk_send_without_enc('identify', x, y) (ret.empty?)? nil: ret end + alias tile_identify ttk_identify + + # remove instate/state/identify method + # to avoid the conflict with widget options + if Tk.const_defined?(:USE_OBSOLETE_TILE_STATE_METHOD) && Tk::USE_OBSOLETE_TILE_STATE_METHOD + alias instate ttk_instate + alias state ttk_state + alias identify ttk_identify + end end ###################################### @@ -200,6 +340,8 @@ module Tk autoload :TPaned, 'tkextlib/tile/tpaned' autoload :Paned, 'tkextlib/tile/tpaned' + autoload :PanedWindow, 'tkextlib/tile/tpaned' + autoload :Panedwindow, 'tkextlib/tile/tpaned' autoload :TProgressbar, 'tkextlib/tile/tprogressbar' autoload :Progressbar, 'tkextlib/tile/tprogressbar' @@ -216,6 +358,8 @@ module Tk autoload :TScrollbar, 'tkextlib/tile/tscrollbar' autoload :Scrollbar, 'tkextlib/tile/tscrollbar' + autoload :XScrollbar, 'tkextlib/tile/tscrollbar' + autoload :YScrollbar, 'tkextlib/tile/tscrollbar' autoload :TSeparator, 'tkextlib/tile/tseparator' autoload :Separator, 'tkextlib/tile/tseparator' @@ -223,8 +367,13 @@ module Tk autoload :TSquare, 'tkextlib/tile/tsquare' autoload :Square, 'tkextlib/tile/tsquare' + autoload :SizeGrip, 'tkextlib/tile/sizegrip' + autoload :Sizegrip, 'tkextlib/tile/sizegrip' + autoload :Treeview, 'tkextlib/tile/treeview' autoload :Style, 'tkextlib/tile/style' end end + +Ttk = Tk::Tile diff --git a/ext/tk/lib/tkextlib/tile/sizegrip.rb b/ext/tk/lib/tkextlib/tile/sizegrip.rb index ea796583b0..c5068919a4 100644 --- a/ext/tk/lib/tkextlib/tile/sizegrip.rb +++ b/ext/tk/lib/tkextlib/tile/sizegrip.rb @@ -9,9 +9,13 @@ module Tk module Tile class SizeGrip < TkWindow end + Sizegrip = SizeGrip end end +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Sizegrip, :TkSizegrip, :TkSizeGrip) + + class Tk::Tile::SizeGrip < TkWindow include Tk::Tile::TileWidget diff --git a/ext/tk/lib/tkextlib/tile/style.rb b/ext/tk/lib/tkextlib/tile/style.rb index 59bc4b0d78..bf8acb34b0 100644 --- a/ext/tk/lib/tkextlib/tile/style.rb +++ b/ext/tk/lib/tkextlib/tile/style.rb @@ -17,6 +17,97 @@ module Tk::Tile::Style end class << Tk::Tile::Style + if Tk::Tile::TILE_SPEC_VERSION_ID < 8 + TkCommandNames = ['style'.freeze].freeze + + # --- Tk::Tile::Style.__define_wrapper_proc_for_compatibility__! --- + # On Ttk (Tile) extension, 'style' command has imcompatible changes + # depend on the version of the extention. It requires modifying the + # Tcl/Tk scripts to define local styles. The rule for modification + # is a simple one. But, if users want to keep compatibility between + # versions of the extension, they will have to contrive to do that. + # It may be troublesome, especially for Ruby/Tk users. + # This method may help such work. This method make some definitions + # on the Tcl/Tk interpreter to work with different version of style + # command format. Please give attention to use this method. It may + # conflict with some definitions on Tcl/Tk scripts. + if Tk::Tile::TILE_SPEC_VERSION_ID < 7 + def __define_wrapper_proc_for_compatibility__! + unless Tk.info(:commands, '::ttk::style').empty? + fail RuntimeError, + "can't define ':ttk::style' command (already exist)" + end + TkCore::INTERP.add_tk_procs('::ttk::style', 'args', <<-'EOS') + if [string equal [lrange $args 0 1] {element create}] { + if [string equal [lindex $args 3] image] { + set spec [lindex $args 4] + set map [lrange $spec 1 end] + if [llength $map] { + # return [eval [concat [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]] + return [uplevel 1 [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]] + } + } + } + # return [eval "::style $args"] + return [uplevel 1 ::style $args] + EOS + ######################### + end + else ### TILE_SPEC_VERSION_ID == 7 + def __define_wrapper_proc_for_compatibility__! + unless Tk.info(:commands, '::ttk::style').empty? + fail RuntimeError, + "can't define ':ttk::style' command (already exist)" + end + TkCore::INTERP.add_tk_procs('::ttk::style', 'args', <<-'EOS') + if [string equal [lrange $args 0 1] {element create}] { + if [string equal [lindex $args 3] image] { + set spec [lindex $args 4] + set map [lrange $spec 1 end] + if [llength $map] { + # return [eval [concat [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]] + return [uplevel 1 [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]] + } + } + } elseif [string equal [lindex $args 0] default] { + # return [eval "::style [lreplace $args 0 0 configure]"] + return [uplevel 1 ::style [lreplace $args 0 0 configure]] + } + # return [eval "::style $args"] + return [uplevel 1 ::style $args] + EOS + ######################### + end + end + else ### TILE_SPEC_VERSION_ID >= 8 + TkCommandNames = ['::ttk::style'.freeze].freeze + + def __define_wrapper_proc_for_compatibility__! + unless Tk.info(:commands, '::style').empty? + fail RuntimeError, "can't define '::style' command (already exist)" + end + TkCore::INTERP.add_tk_procs('::style', 'args', <<-'EOS') + if [string equal [lrange $args 0 1] {element create}] { + if [string equal [lindex $args 3] image] { + set name [lindex $args 4] + set opts [lrange $args 5 end] + set idx [lsearch $opts -map] + if {$idx >= 0 && [expr $idx % 2 == 0]} { + # return [eval [concat [list ::ttk::style element create [lindex $args 2] image [concat $name [lindex $opts [expr $idx + 1]]]] [lreplace $opts $idx [expr $idx + 1]]]] + return [uplevel 1 [list ::ttk::style element create [lindex $args 2] image [concat $name [lindex $opts [expr $idx + 1]]]] [lreplace $opts $idx [expr $idx + 1]]] + } + } + } elseif [string equal [lindex $args 0] default] { + # return [eval "::ttk::style [lreplace $args 0 0 configure]"] + return [uplevel 1 ::ttk::style [lreplace $args 0 0 configure]] + } + # return [eval "::ttk::style $args"] + return [uplevel 1 ::ttk::style $args] + EOS + ######################### + end + end + def configure(style=nil, keys=nil) if style.kind_of?(Hash) keys = style @@ -31,9 +122,9 @@ class << Tk::Tile::Style end if keys && keys != None - tk_call('style', sub_cmd, style, *hash_kv(keys)) + tk_call(TkCommandNames[0], sub_cmd, style, *hash_kv(keys)) else - tk_call('style', sub_cmd, style) + tk_call(TkCommandNames[0], sub_cmd, style) end end alias default configure @@ -46,14 +137,33 @@ class << Tk::Tile::Style style = '.' unless style if keys && keys != None - tk_call('style', 'map', style, *hash_kv(keys)) + if keys.kind_of?(Hash) + tk_call(TkCommandNames[0], 'map', style, *hash_kv(keys)) + else + simplelist(tk_call(TkCommandNames[0], 'map', style, '-' << keys.to_s)) + end else - tk_call('style', 'map', style) + ret = {} + Hash[*(simplelist(tk_call(TkCommandNames[0], 'map', style)))].each{|k, v| + ret[k[1..-1]] = list(v) + } + ret end end + alias map_configure map + + def map_configinfo(style=nil, key=None) + style = '.' unless style + map(style, key) + end + + def map_default_configinfo(key=None) + map('.', key) + end def lookup(style, opt, state=None, fallback_value=None) - tk_call('style', 'lookup', style, '-' << opt.to_s, state, fallback_value) + tk_call(TkCommandNames[0], 'lookup', style, + '-' << opt.to_s, state, fallback_value) end include Tk::Tile::ParseStyleLayout @@ -66,42 +176,93 @@ class << Tk::Tile::Style style = '.' unless style if spec - tk_call('style', 'layout', style, spec) + tk_call(TkCommandNames[0], 'layout', style, spec) else - _style_layout(list(tk_call('style', 'layout', style))) + _style_layout(list(tk_call(TkCommandNames[0], 'layout', style))) end end def element_create(name, type, *args) - tk_call('style', 'element', 'create', name, type, *args) + if type == 'image' || type == :image + element_create_image(name, *args) + else + tk_call(TkCommandNames[0], 'element', 'create', name, type, *args) + end + end + + def element_create_image(name, *args) + fail ArgumentError, 'Must supply a base image' unless (spec = args.shift) + if (opts = args.shift) + if opts.kind_of?(Hash) + opts = _symbolkey2str(opts) + else + fail ArgumentError, 'bad option' + end + end + fail ArgumentError, 'too many arguments' unless args.empty? + + if spec.kind_of?(Array) + # probably, command format is tile 0.8+ (Tcl/Tk8.5+) style + if Tk::Tile::TILE_SPEC_VERSION_ID >= 8 + if opts + tk_call(TkCommandNames[0], + 'element', 'create', name, 'image', spec, opts) + else + tk_call(TkCommandNames[0], 'element', 'create', name, 'image', spec) + end + else + fail ArgumentError, 'illegal arguments' if opts.key?('map') + base = spec.shift + opts['map'] = spec + tk_call(TkCommandNames[0], + 'element', 'create', name, 'image', base, opts) + end + else + # probably, command format is tile 0.7.8 or older style + if Tk::Tile::TILE_SPEC_VERSION_ID >= 8 + spec = [spec, *(opts.delete('map'))] if opts.key?('map') + end + if opts + tk_call(TkCommandNames[0], + 'element', 'create', name, 'image', spec, opts) + else + tk_call(TkCommandNames[0], 'element', 'create', name, 'image', spec) + end + end end def element_names() - list(tk_call('style', 'element', 'names')) + list(tk_call(TkCommandNames[0], 'element', 'names')) end def element_options(elem) - simplelist(tk_call('style', 'element', 'options', elem)) + simplelist(tk_call(TkCommandNames[0], 'element', 'options', elem)) end def theme_create(name, keys=nil) + name = name.to_s if keys && keys != None - tk_call('style', 'theme', 'create', name, *hash_kv(keys)) + tk_call(TkCommandNames[0], 'theme', 'create', name, *hash_kv(keys)) else - tk_call('style', 'theme', 'create', name) + tk_call(TkCommandNames[0], 'theme', 'create', name) end + name end def theme_settings(name, cmd=nil, &b) + name = name.to_s cmd = Proc.new(&b) if !cmd && b - tk_call('style', 'theme', 'settings', name, cmd) + tk_call(TkCommandNames[0], 'theme', 'settings', name, cmd) + name end def theme_names() - list(tk_call('style', 'theme', 'names')) + list(tk_call(TkCommandNames[0], 'theme', 'names')) end def theme_use(name) - tk_call('style', 'theme', 'use', name) + name = name.to_s + tk_call(TkCommandNames[0], 'theme', 'use', name) + name end end diff --git a/ext/tk/lib/tkextlib/tile/tbutton.rb b/ext/tk/lib/tkextlib/tile/tbutton.rb index 1142a27100..5d7db10fe9 100644 --- a/ext/tk/lib/tkextlib/tile/tbutton.rb +++ b/ext/tk/lib/tkextlib/tile/tbutton.rb @@ -7,13 +7,16 @@ require 'tkextlib/tile.rb' module Tk module Tile - class TButton < TkButton + class TButton < Tk::Button end Button = TButton end end -class Tk::Tile::TButton < TkButton +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Button, :TkButton) + + +class Tk::Tile::TButton < Tk::Button include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE diff --git a/ext/tk/lib/tkextlib/tile/tcheckbutton.rb b/ext/tk/lib/tkextlib/tile/tcheckbutton.rb index fce799683d..172225fcec 100644 --- a/ext/tk/lib/tkextlib/tile/tcheckbutton.rb +++ b/ext/tk/lib/tkextlib/tile/tcheckbutton.rb @@ -7,7 +7,7 @@ require 'tkextlib/tile.rb' module Tk module Tile - class TCheckButton < TkCheckButton + class TCheckButton < Tk::CheckButton end TCheckbutton = TCheckButton CheckButton = TCheckButton @@ -15,7 +15,11 @@ module Tk end end -class Tk::Tile::TCheckButton < TkCheckButton +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Checkbutton, + :TkCheckbutton, :TkCheckButton) + + +class Tk::Tile::TCheckButton < Tk::CheckButton include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE diff --git a/ext/tk/lib/tkextlib/tile/tcombobox.rb b/ext/tk/lib/tkextlib/tile/tcombobox.rb index e8e042fbd9..b64372f1c9 100644 --- a/ext/tk/lib/tkextlib/tile/tcombobox.rb +++ b/ext/tk/lib/tkextlib/tile/tcombobox.rb @@ -13,6 +13,9 @@ module Tk end end +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Combobox, :TkCombobox) + + class Tk::Tile::TCombobox < Tk::Tile::TEntry include Tk::Tile::TileWidget diff --git a/ext/tk/lib/tkextlib/tile/tentry.rb b/ext/tk/lib/tkextlib/tile/tentry.rb index 4d57ce7756..4b221fcb88 100644 --- a/ext/tk/lib/tkextlib/tile/tentry.rb +++ b/ext/tk/lib/tkextlib/tile/tentry.rb @@ -7,13 +7,16 @@ require 'tkextlib/tile.rb' module Tk module Tile - class TEntry < TkEntry + class TEntry < Tk::Entry end Entry = TEntry end end -class Tk::Tile::TEntry < TkEntry +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Entry, :TkEntry) + + +class Tk::Tile::TEntry < Tk::Entry include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE diff --git a/ext/tk/lib/tkextlib/tile/tframe.rb b/ext/tk/lib/tkextlib/tile/tframe.rb index 691c9c42af..3b5f98bb6e 100644 --- a/ext/tk/lib/tkextlib/tile/tframe.rb +++ b/ext/tk/lib/tkextlib/tile/tframe.rb @@ -7,13 +7,16 @@ require 'tkextlib/tile.rb' module Tk module Tile - class TFrame < TkFrame + class TFrame < Tk::Frame end Frame = TFrame end end -class Tk::Tile::TFrame < TkFrame +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Frame, :TkFrame) + + +class Tk::Tile::TFrame < Tk::Frame include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE diff --git a/ext/tk/lib/tkextlib/tile/tlabel.rb b/ext/tk/lib/tkextlib/tile/tlabel.rb index 4111d1906a..7d074d3842 100644 --- a/ext/tk/lib/tkextlib/tile/tlabel.rb +++ b/ext/tk/lib/tkextlib/tile/tlabel.rb @@ -7,13 +7,16 @@ require 'tkextlib/tile.rb' module Tk module Tile - class TLabel < TkLabel + class TLabel < Tk::Label end Label = TLabel end end -class Tk::Tile::TLabel < TkLabel +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Label, :TkLabel) + + +class Tk::Tile::TLabel < Tk::Label include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE diff --git a/ext/tk/lib/tkextlib/tile/tlabelframe.rb b/ext/tk/lib/tkextlib/tile/tlabelframe.rb index 8981232b25..cff66d8658 100644 --- a/ext/tk/lib/tkextlib/tile/tlabelframe.rb +++ b/ext/tk/lib/tkextlib/tile/tlabelframe.rb @@ -9,10 +9,16 @@ module Tk module Tile class TLabelframe < Tk::Tile::TFrame end - Labelframe = TLabelframe + TLabelFrame = TLabelframe + Labelframe = TLabelframe + LabelFrame = TLabelframe end end +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Labelframe, + :TkLabelframe, :TkLabelFrame) + + class Tk::Tile::TLabelframe < Tk::Tile::TFrame include Tk::Tile::TileWidget diff --git a/ext/tk/lib/tkextlib/tile/tmenubutton.rb b/ext/tk/lib/tkextlib/tile/tmenubutton.rb index 4b81fa1c81..7c6ab28e52 100644 --- a/ext/tk/lib/tkextlib/tile/tmenubutton.rb +++ b/ext/tk/lib/tkextlib/tile/tmenubutton.rb @@ -7,13 +7,19 @@ require 'tkextlib/tile.rb' module Tk module Tile - class TMenubutton < TkMenubutton + class TMenubutton < Tk::Menubutton end - Menubutton = TMenubutton + TMenuButton = TMenubutton + Menubutton = TMenubutton + MenuButton = TMenubutton end end -class Tk::Tile::TMenubutton < TkMenubutton +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Menubutton, + :TkMenubutton, :TkMenuButton) + + +class Tk::Tile::TMenubutton < Tk::Menubutton include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE diff --git a/ext/tk/lib/tkextlib/tile/tnotebook.rb b/ext/tk/lib/tkextlib/tile/tnotebook.rb index a928e64b61..76f225c579 100644 --- a/ext/tk/lib/tkextlib/tile/tnotebook.rb +++ b/ext/tk/lib/tkextlib/tile/tnotebook.rb @@ -13,6 +13,9 @@ module Tk end end +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Notebook, :TkNotebook) + + class Tk::Tile::TNotebook < TkWindow ################################ include TkItemConfigMethod diff --git a/ext/tk/lib/tkextlib/tile/tpaned.rb b/ext/tk/lib/tkextlib/tile/tpaned.rb index 11178b19d3..342b54d253 100644 --- a/ext/tk/lib/tkextlib/tile/tpaned.rb +++ b/ext/tk/lib/tkextlib/tile/tpaned.rb @@ -9,15 +9,23 @@ module Tk module Tile class TPaned < TkWindow end - Paned = TPaned + PanedWindow = Panedwindow = Paned = TPaned end end +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Panedwindow, + :TkPanedwindow, :TkPanedWindow) + + class Tk::Tile::TPaned < TkWindow include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE - TkCommandNames = ['::ttk::paned'.freeze].freeze + if Tk::Tile::TILE_SPEC_VERSION_ID < 8 + TkCommandNames = ['::ttk::paned'.freeze].freeze + else + TkCommandNames = ['::ttk::panedwindow'.freeze].freeze + end else TkCommandNames = ['::tpaned'.freeze].freeze end diff --git a/ext/tk/lib/tkextlib/tile/tprogressbar.rb b/ext/tk/lib/tkextlib/tile/tprogressbar.rb index 36c1c75c23..f786d370dd 100644 --- a/ext/tk/lib/tkextlib/tile/tprogressbar.rb +++ b/ext/tk/lib/tkextlib/tile/tprogressbar.rb @@ -13,6 +13,9 @@ module Tk end end +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Progressbar, :TkProgressbar) + + class Tk::Tile::TProgressbar include Tk::Tile::TileWidget diff --git a/ext/tk/lib/tkextlib/tile/tradiobutton.rb b/ext/tk/lib/tkextlib/tile/tradiobutton.rb index e2f614cb97..d653a6d256 100644 --- a/ext/tk/lib/tkextlib/tile/tradiobutton.rb +++ b/ext/tk/lib/tkextlib/tile/tradiobutton.rb @@ -7,7 +7,7 @@ require 'tkextlib/tile.rb' module Tk module Tile - class TRadioButton < TkRadioButton + class TRadioButton < Tk::RadioButton end TRadiobutton = TRadioButton RadioButton = TRadioButton @@ -15,7 +15,11 @@ module Tk end end -class Tk::Tile::TRadioButton < TkRadioButton +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Radiobutton, + :TkRadiobutton, :TkRadioButton) + + +class Tk::Tile::TRadioButton < Tk::RadioButton include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE diff --git a/ext/tk/lib/tkextlib/tile/treeview.rb b/ext/tk/lib/tkextlib/tile/treeview.rb index 68e478896c..7f31b9c233 100644 --- a/ext/tk/lib/tkextlib/tile/treeview.rb +++ b/ext/tk/lib/tkextlib/tile/treeview.rb @@ -12,6 +12,9 @@ module Tk end end +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Treeview, :TkTreeview) + + module Tk::Tile::TreeviewConfig include TkItemConfigMethod @@ -378,7 +381,7 @@ module Tk::Tile::TreeviewConfig when :item, 'item' ['width'] when :column, 'column' - super(id[1]) + super(id[1]) + ['minwidth'] when :tag, 'tag' super(id[1]) when :heading, 'heading' @@ -410,7 +413,7 @@ module Tk::Tile::TreeviewConfig when :item, 'item' ['open'] when :column, 'column' - super(id[1]) + super(id[1]) + ['stretch'] when :tag, 'tag' super(id[1]) when :heading, 'heading' @@ -614,30 +617,43 @@ end class Tk::Tile::Treeview::Item < TkObject ItemID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ Tk::Tile::Treeview::Item::ItemID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Item::ItemID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::Tile::Treeview::Item::ItemID_TBL[tpath] - (Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id])? \ - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]: id + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] + (Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id])? \ + Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]: id + else + id + end + } end def self.assign(tree, id) tpath = tree.path - if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] && - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] - return Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] - end + obj = nil + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] && + Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] + return Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] + end - obj = self.allocate - obj.instance_eval{ - @parent = @t = tree - @tpath = tpath - @path = @id = id + obj = self.allocate + obj.instance_eval{ + @parent = @t = tree + @tpath = tpath + @path = @id = id + } + Tk::Tile::Treeview::Item::ItemID_TBL[tpath] ||= {} + Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] = obj } - ItemID_TBL[tpath] = {} unless ItemID_TBL[tpath] - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] = obj obj end @@ -666,8 +682,10 @@ class Tk::Tile::Treeview::Item < TkObject @parent = @t = tree @tpath = tree.path @path = @id = _insert_item(@t, parent_item, idx, keys) - ItemID_TBL[@tpath] = {} unless ItemID_TBL[@tpath] - ItemID_TBL[@tpath][@id] = self + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + ItemID_TBL[@tpath] = {} unless ItemID_TBL[@tpath] + ItemID_TBL[@tpath][@id] = self + } end def id @id @@ -801,22 +819,35 @@ end class Tk::Tile::Treeview::Root < Tk::Tile::Treeview::Item def self.new(tree, keys = {}) tpath = tree.path - if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] && - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][''] - Tk::Tile::Treeview::Item::ItemID_TBL[tpath][''] - else - super(tree, keys) - end + obj = nil + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] && + Tk::Tile::Treeview::Item::ItemID_TBL[tpath][''] + obj = Tk::Tile::Treeview::Item::ItemID_TBL[tpath][''] + else + #super(tree, keys) + (obj = self.allocate).instance_eval{ + @parent = @t = tree + @tpath = tree.path + @path = @id = '' + Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] ||= {} + Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self + } + end + } + obj.configure(keys) if keys && ! keys.empty? + obj end def initialize(tree, keys = {}) + # dummy:: not called by 'new' method @parent = @t = tree @tpath = tree.path @path = @id = '' - unless Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] - Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] = {} - end - Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] ||= {} + Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self + } end end @@ -826,24 +857,42 @@ class Tk::Tile::Treeview::Tag < TkObject include TkTreatTagFont TagID_TBL = TkCore::INTERP.create_table - Tag_ID = ['tile_treeview_tag'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ Tk::Tile::Treeview::Tag::TagID_TBL.clear } + (Tag_ID = ['tile_treeview_tag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + Tk::Tile::Treeview::Tag::TagID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Tag::TagID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::Tile::Treeview::Tag::TagID_TBL[tpath] - (Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id])? \ - Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id]: id + Tk::Tile::Treeview::Tag::TagID_TBL.mutex.synchronize{ + if Tk::Tile::Treeview::Tag::TagID_TBL[tpath] + (Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id])? \ + Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id]: id + else + id + end + } end def initialize(tree, keys=nil) @parent = @t = tree @tpath = tree.path - @path = @id = Tag_ID.join(TkCore::INTERP._ip_id_) - TagID_TBL[@tpath] = {} unless TagID_TBL[@tpath] - TagID_TBL[@tpath][@id] = self - Tag_ID[1].succ! + Tag_ID.mutex.synchronize{ + @path = @id = Tag_ID.join(TkCore::INTERP._ip_id_) + Tag_ID[1].succ! + } + TagID_TBL.mutex.synchronize{ + TagID_TBL[@tpath] = {} unless TagID_TBL[@tpath] + TagID_TBL[@tpath][@id] = self + } if keys && keys != None tk_call_without_enc(@tpath, 'tag', 'configure', *hash_kv(keys, true)) end @@ -916,8 +965,12 @@ class Tk::Tile::Treeview < TkWindow WidgetClassNames[WidgetClassName] = self def __destroy_hook__ - Tk::Tile::Treeview::Item::ItemID_TBL.delete(@path) - Tk::Tile::Treeview::Tag::ItemID_TBL.delete(@path) + Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Item::ItemID_TBL.delete(@path) + } + Tk::Tile::Treeview::Tag::ItemID_TBL.mutex.synchronize{ + Tk::Tile::Treeview::Tag::ItemID_TBL.delete(@path) + } end def self.style(*args) diff --git a/ext/tk/lib/tkextlib/tile/tscale.rb b/ext/tk/lib/tkextlib/tile/tscale.rb index 7ec72e3515..2c46fd9bd4 100644 --- a/ext/tk/lib/tkextlib/tile/tscale.rb +++ b/ext/tk/lib/tkextlib/tile/tscale.rb @@ -7,7 +7,7 @@ require 'tkextlib/tile.rb' module Tk module Tile - class TScale < TkScale + class TScale < Tk::Scale end Scale = TScale @@ -17,7 +17,10 @@ module Tk end end -class Tk::Tile::TScale < TkScale +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Scale, :TkScale) + + +class Tk::Tile::TScale < Tk::Scale include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE diff --git a/ext/tk/lib/tkextlib/tile/tscrollbar.rb b/ext/tk/lib/tkextlib/tile/tscrollbar.rb index bd49ae18e3..163b8f4713 100644 --- a/ext/tk/lib/tkextlib/tile/tscrollbar.rb +++ b/ext/tk/lib/tkextlib/tile/tscrollbar.rb @@ -7,13 +7,16 @@ require 'tkextlib/tile.rb' module Tk module Tile - class TScrollbar < TkScrollbar + class TScrollbar < Tk::Scrollbar end Scrollbar = TScrollbar end end -class Tk::Tile::TScrollbar < TkScrollbar +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Scrollbar, :TkScrollbar) + + +class Tk::Tile::TScrollbar < Tk::Scrollbar include Tk::Tile::TileWidget if Tk::Tile::USE_TTK_NAMESPACE @@ -28,3 +31,24 @@ class Tk::Tile::TScrollbar < TkScrollbar [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.') end end + +class Tk::Tile::XScrollbar < Tk::Tile::TScrollbar + def create_self(keys) + keys = {} unless keys + keys['orient'] = 'horizontal' + super(keys) + end + private :create_self +end + +class Tk::Tile::YScrollbar < Tk::Tile::TScrollbar + def create_self(keys) + keys = {} unless keys + keys['orient'] = 'vertical' + super(keys) + end + private :create_self +end + +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::XScrollbar, :TkXScrollbar) +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::YScrollbar, :TkYScrollbar) diff --git a/ext/tk/lib/tkextlib/tile/tseparator.rb b/ext/tk/lib/tkextlib/tile/tseparator.rb index ca731d4e5b..30fae2c525 100644 --- a/ext/tk/lib/tkextlib/tile/tseparator.rb +++ b/ext/tk/lib/tkextlib/tile/tseparator.rb @@ -13,6 +13,9 @@ module Tk end end +Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Separator, :TkSeparator) + + class Tk::Tile::TSeparator < TkWindow include Tk::Tile::TileWidget diff --git a/ext/tk/lib/tkextlib/tkDND/tkdnd.rb b/ext/tk/lib/tkextlib/tkDND/tkdnd.rb index a040532eb6..ea91d3d1f4 100644 --- a/ext/tk/lib/tkextlib/tkDND/tkdnd.rb +++ b/ext/tk/lib/tkextlib/tkDND/tkdnd.rb @@ -57,6 +57,22 @@ module Tk nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + # setup tables _setup_subst_table(KEY_TBL, PROC_TBL); end diff --git a/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb b/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb index 8527f61df1..d893a83cf2 100644 --- a/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb +++ b/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb @@ -39,7 +39,10 @@ class Tk::HTML_Widget::ClippingWindow WidgetClassNames[WidgetClassName] = self HtmlClip_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ HtmlClip_TBL.clear } + + TkCore::INTERP.init_ip_env{ + HtmlClip_TBL.mutex.synchronize{ HtmlClip_TBL.clear } + } def self.new(parent, keys={}) if parent.kind_of?(Hash) @@ -54,7 +57,9 @@ class Tk::HTML_Widget::ClippingWindow else ppath = '' end - return HtmlClip_TBL[ppath] if HtmlClip_TBL[ppath] + HtmlClip_TBL.mutex.synchronize{ + return HtmlClip_TBL[ppath] if HtmlClip_TBL[ppath] + } widgetname = keys.delete('widgetname') if widgetname =~ /^(.*)\.[^.]+$/ @@ -62,7 +67,9 @@ class Tk::HTML_Widget::ClippingWindow if ppath2[0] != ?. ppath2 = ppath + '.' + ppath2 end - return HtmlClip_TBL[ppath2] if HtmlClip_TBL[ppath2] + HtmlClip_TBL.mutex.synchronize{ + return HtmlClip_TBL[ppath2] if HtmlClip_TBL[ppath2] + } ppath = ppath2 end @@ -79,7 +86,9 @@ class Tk::HTML_Widget::ClippingWindow @parent = parent @ppath = parent.path @path = @id = @ppath + '.x' - HtmlClip_TBL[@ppath] = self + HtmlClip_TBL.mutex.synchronize{ + HtmlClip_TBL[@ppath] = self + } end def method_missing(m, *args, &b) diff --git a/ext/tk/lib/tkextlib/tktable/tktable.rb b/ext/tk/lib/tkextlib/tktable/tktable.rb index 4edaabc847..fb8a8b0f72 100644 --- a/ext/tk/lib/tkextlib/tktable/tktable.rb +++ b/ext/tk/lib/tkextlib/tktable/tktable.rb @@ -118,23 +118,39 @@ class Tk::TkTable::CellTag include TkTreatTagFont CellTagID_TBL = TkCore::INTERP.create_table - CellTag_ID = ['tktbl:celltag'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ CellTagID_TBL.clear } + (CellTag_ID = ['tktbl:celltag'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + CellTagID_TBL.mutex.synchronize{ CellTagID_TBL.clear } + } def self.id2obj(table, id) tpath = table.path - return id unless CellTagID_TBL[tpath] - CellTagID_TBL[tpath][id]? CellTagID_TBL[tpath][id] : id + CellTagID_TBL.mutex.synchronize{ + if CellTagID_TBL[tpath] + CellTagID_TBL[tpath][id]? CellTagID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, keys=nil) @parent = @t = parent @tpath - parent.path - @path = @id = CellTag_ID.join(TkCore::INTERP._ip_id_) - CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] - CellTagID_TBL[@tpath][@id] = self - CellTag_ID[1].succ! + CellTag_ID.mutex.synchronize{ + @path = @id = CellTag_ID.join(TkCore::INTERP._ip_id_) + CellTag_ID[1].succ! + } + CellTagID_TBL.mutex.synchronize{ + CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] + CellTagID_TBL[@tpath][@id] = self + } configure(keys) if keys end @@ -144,7 +160,9 @@ class Tk::TkTable::CellTag def destroy tk_call(@tpath, 'tag', 'delete', @id) - CellTagID_TBL[@tpath].delete(@id) if CellTagID_TBL[@tpath] + CellTagID_TBL.mutex.synchronize{ + CellTagID_TBL[@tpath].delete(@id) if CellTagID_TBL[@tpath] + } self end alias delete destroy @@ -189,22 +207,35 @@ end class Tk::TkTable::NamedCellTag < Tk::TkTable::CellTag def self.new(parent, name, keys=nil) - if CellTagID_TBL[parent.path] && CellTagID_TBL[parent.path][name] - cell = CellTagID_TBL[parent.path][name] - cell.configure(keys) if keys - return cell - else - super(parent, name, keys) - end + obj = nil + CellTagID_TBL.mutex.synchronize{ + if CellTagID_TBL[parent.path] && CellTagID_TBL[parent.path][name] + obj = CellTagID_TBL[parent.path][name] + else + #super(parent, name, keys) + (obj = self.allocate).instance_eval{ + @parent = @t = parent + @tpath = parent.path + @path = @id = name + CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] + CellTagID_TBL[@tpath][@id] = self + } + end + } + obj.configure(keys) if keys && ! keys.empty? + obj end def initialize(parent, name, keys=nil) + # dummy:: not called by 'new' method @parent = @t = parent - @tpath - parent.path + @tpath = parent.path @path = @id = name - CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] - CellTagID_TBL[@tpath][@id] = self - configure(keys) if keys + CellTagID_TBL.mutex.synchronize{ + CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath] + CellTagID_TBL[@tpath][@id] = self + } + configure(keys) if keys && ! keys.empty? end end @@ -220,7 +251,9 @@ class Tk::TkTable include Tk::ValidateConfigure def __destroy_hook__ - Tk::TkTable::CelTag::CellTagID_TBL.delete(@path) + Tk::TkTable::CelTag::CellTagID_TBL.mutex.synchronize{ + Tk::TkTable::CelTag::CellTagID_TBL.delete(@path) + } end def __boolval_optkeys @@ -258,6 +291,22 @@ class Tk::TkTable nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -291,6 +340,22 @@ class Tk::TkTable nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -322,6 +387,22 @@ class Tk::TkTable nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) @@ -356,6 +437,22 @@ class Tk::TkTable nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); end @@ -746,15 +843,17 @@ class Tk::TkTable end def tagid2obj(tagid) - if Tk::TkTable::CellTag::CellTagID_TBL.key?(@path) - if Tk::TkTable::CellTag::CellTagID_TBL[@path].key?(tagid) - Tk::TkTable::CellTag::CellTagID_TBL[@path][tagid] + Tk::TkTable::CellTag::CellTagID_TBL.mutex.synchronize{ + if Tk::TkTable::CellTag::CellTagID_TBL.key?(@path) + if Tk::TkTable::CellTag::CellTagID_TBL[@path].key?(tagid) + Tk::TkTable::CellTag::CellTagID_TBL[@path][tagid] + else + tagid + end else tagid end - else - tagid - end + } end def tag_cell(tag, *cells) @@ -775,13 +874,15 @@ class Tk::TkTable end def tag_delete(tag) tk_send('tag', 'delete', tagid(tag)) - if Tk::TkTable::CellTag::CellTagID_TBL[@path] - if tag.kind_of? Tk::TkTable::CellTag - Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag.id) - else - Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag) + Tk::TkTable::CellTag::CellTagID_TBL.mutex.synchronize{ + if Tk::TkTable::CellTag::CellTagID_TBL[@path] + if tag.kind_of? Tk::TkTable::CellTag + Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag.id) + else + Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag) + end end - end + } self end def tag_exist?(tag) diff --git a/ext/tk/lib/tkextlib/tktrans/tktrans.rb b/ext/tk/lib/tkextlib/tktrans/tktrans.rb index 665c57af0c..e051c09211 100644 --- a/ext/tk/lib/tkextlib/tktrans/tktrans.rb +++ b/ext/tk/lib/tkextlib/tktrans/tktrans.rb @@ -39,7 +39,7 @@ class TkWindow end end -class TkRoot +class Tk::Root undef tktrans_set_image, tktrans_get_image def tktrans_set_image(img) @@ -51,7 +51,7 @@ class TkRoot end end -class TkToplevel +class Tk::Toplevel undef tktrans_set_image, tktrans_get_image def tktrans_set_image(img) diff --git a/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb b/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb index 12f7cffabf..b72b157dcd 100644 --- a/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb +++ b/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb @@ -137,6 +137,22 @@ class Tk::TreeCtrl::NotifyEvent nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + # setup tables to be used by scan_args, _get_subst_key, _get_all_subst_keys # # _get_subst_key() and _get_all_subst_keys() generates key-string @@ -544,10 +560,18 @@ class Tk::TreeCtrl ######################### def __destroy_hook__ - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.delete(@path) - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.delete(@path) - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.delete(@path) - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.delete(@path) + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.delete(@path) + } + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.delete(@path) + } + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.delete(@path) + } + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.delete(@path) + } end ######################### @@ -638,9 +662,11 @@ class Tk::TreeCtrl end def column_delete(idx) - if Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path] - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path].delete(idx) - end + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path] + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path].delete(idx) + end + } tk_send('column', 'delete', idx) self end @@ -750,11 +776,13 @@ class Tk::TreeCtrl end def element_delete(*elems) - if Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path] - elems.each{|elem| - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path].delete(elem) - } - end + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path] + elems.each{|elem| + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path].delete(elem) + } + end + } tk_send('element', 'delete', *elems) self end @@ -885,22 +913,25 @@ class Tk::TreeCtrl def _erase_children(item) item_children(item).each{|i| _erase_children(i)} + # table is already locked Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path].delete(item) end private :_erase_children def item_delete(first, last=None) - if Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path] - if first == 'all' || first == :all || last == 'all' || last == :all - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path].clear - elsif last == None - _erase_children(first) - else - self.range(first, last).each{|id| - _erase_children(id) - } + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path] + if first == 'all' || first == :all || last == 'all' || last == :all + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path].clear + elsif last == None + _erase_children(first) + else + self.range(first, last).each{|id| + _erase_children(id) + } + end end - end + } tk_send('item', 'delete', first, last) self end @@ -1520,11 +1551,13 @@ class Tk::TreeCtrl end def style_delete(*args) - if Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path] - args.each{|sty| - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path].delete(sty) - } - end + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path] + args.each{|sty| + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path].delete(sty) + } + end + } tk_send('style', 'delete', *args) self end @@ -1608,15 +1641,29 @@ end class Tk::TreeCtrl::Column < TkObject TreeCtrlColumnID_TBL = TkCore::INTERP.create_table - TreeCtrlColumnID = ['treectrl_column'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.clear} + (TreeCtrlColumnID = ['treectrl_column'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath] - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id]? \ - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id] : id + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath] + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id]? \ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, keys={}) @@ -1625,17 +1672,19 @@ class Tk::TreeCtrl::Column < TkObject keys = _symbolkey2str(keys) - @path = @id = - keys.delete('tag') || - Tk::TreeCtrl::Column::TreeCtrlColumnID.join(TkCore::INTERP._ip_id_) + Tk::TreeCtrl::Column::TreeCtrlColumnID.mutex.synchronize{ + @path = @id = + keys.delete('tag') || + Tk::TreeCtrl::Column::TreeCtrlColumnID.join(TkCore::INTERP._ip_id_) + Tk::TreeCtrl::Column::TreeCtrlColumnID[1].succ! + } keys['tag'] = @id - unless Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath] - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath] = {} - end - Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath][@id] = self - Tk::TreeCtrl::Column::TreeCtrlColumnID[1].succ! + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath] ||= {} + Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath][@id] = self + } @tree.column_create(keys) end @@ -1692,11 +1741,18 @@ end class Tk::TreeCtrl::Element < TkObject TreeCtrlElementID_TBL = TkCore::INTERP.create_table - TreeCtrlElementID = ['treectrl_element'.freeze, '00000'.taint].freeze + + (TreeCtrlElementID = ['treectrl_element'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } TreeCtrlElemTypeToClass = {} TkCore::INTERP.init_ip_env{ - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.clear + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.clear + } } def self.type2class(type) @@ -1705,22 +1761,30 @@ class Tk::TreeCtrl::Element < TkObject def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath] - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath][id]? \ + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath] + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath][id]? \ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, type, keys=nil) @tree = parent @tpath = parent.path @type = type.to_s - @path = @id = - Tk::TreeCtrl::Element::TreeCtrlElementID.join(TkCore::INTERP._ip_id_) - unless Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath] - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath] = {} - end - Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath][@id] = self - Tk::TreeCtrl::Element::TreeCtrlElementID[1].succ! + Tk::TreeCtrl::Element::TreeCtrlElementID.mutex.synchronize{ + @path = @id = + Tk::TreeCtrl::Element::TreeCtrlElementID.join(TkCore::INTERP._ip_id_) + Tk::TreeCtrl::Element::TreeCtrlElementID[1].succ! + } + + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath] ||= {} + Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath][@id] = self + } @tree.element_create(@id, @type, keys) end @@ -1800,13 +1864,22 @@ end class Tk::TreeCtrl::Item < TkObject TreeCtrlItemID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.clear} + TkCore::INTERP.init_ip_env{ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath] - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id]? \ - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id] : id + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath] + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id]? \ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, keys={}) @@ -1814,10 +1887,10 @@ class Tk::TreeCtrl::Item < TkObject @tpath = parent.path @path = @id = @tree.item_create(keys) - unless Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath] - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath] = {} - end - Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath][@id] = self + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath] ||= {} + Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath][@id] = self + } end def id @@ -2088,27 +2161,45 @@ end class Tk::TreeCtrl::Style < TkObject TreeCtrlStyleID_TBL = TkCore::INTERP.create_table - TreeCtrlStyleID = ['treectrl_style'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.clear } + (TreeCtrlStyleID = ['treectrl_style'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.clear + } + } def self.id2obj(tree, id) tpath = tree.path - return id unless Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath] - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id]? \ - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id] : id + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + if Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath] + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id]? \ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id] : id + else + id + end + } end def initialize(parent, keys=nil) @tree = parent @tpath = parent.path - @path = @id = - Tk::TreeCtrl::Style::TreeCtrlStyleID.join(TkCore::INTERP._ip_id_) - unless Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath] - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath] = {} - end - Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath][@id] = self - Tk::TreeCtrl::Style::TreeCtrlStyleID[1].succ! + + Tk::TreeCtrl::Style::TreeCtrlStyleID.mutex.synchronize{ + @path = @id = + Tk::TreeCtrl::Style::TreeCtrlStyleID.join(TkCore::INTERP._ip_id_) + Tk::TreeCtrl::Style::TreeCtrlStyleID[1].succ! + } + + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{ + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath] ||= {} + Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath][@id] = self + } @tree.style_create(@id, keys) end diff --git a/ext/tk/lib/tkextlib/version.rb b/ext/tk/lib/tkextlib/version.rb index c7816fd4a5..3542c79dbe 100644 --- a/ext/tk/lib/tkextlib/version.rb +++ b/ext/tk/lib/tkextlib/version.rb @@ -2,5 +2,5 @@ # release date of tkextlib # module Tk - Tkextlib_RELEASE_DATE = '2007-05-26'.freeze + Tkextlib_RELEASE_DATE = '2008-03-29'.freeze end diff --git a/ext/tk/lib/tkextlib/vu/pie.rb b/ext/tk/lib/tkextlib/vu/pie.rb index 78f3fa54da..1975803db1 100644 --- a/ext/tk/lib/tkextlib/vu/pie.rb +++ b/ext/tk/lib/tkextlib/vu/pie.rb @@ -116,13 +116,26 @@ end class Tk::Vu::PieSlice SliceID_TBL = TkCore::INTERP.create_table - Pie_Slice_ID = ['vu:pie'.freeze, '00000'.taint].freeze - TkCore::INTERP.init_ip_env{ SliceID_TBL.clear } + + (Pie_Slice_ID = ['vu:pie'.freeze, '00000'.taint]).instance_eval{ + @mutex = Mutex.new + def mutex; @mutex; end + freeze + } + + TkCore::INTERP.init_ip_env{ + SliceID_TBL.mutex.synchronize{ SliceID_TBL.clear } + } def self.id2obj(pie, id) pie_path = pie.path - return id unless SliceID_TBL[pie_path] - SliceID_TBL[pie_path][id]? SliceID_TBL[pie_path][id]: id + SliceID_TBL.mutex.synchronize{ + if SliceID_TBL[pie_path] + SliceID_TBL[pie_path][id]? SliceID_TBL[pie_path][id]: id + else + id + end + } end def initialize(parent, *args) @@ -131,10 +144,14 @@ class Tk::Vu::PieSlice end @parent = @pie = parent @ppath = parent.path - @path = @id = Pie_Slice_ID.join(TkCore::INTERP._ip_id_) - SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] - SliceID_TBL[@ppath][@id] = self - Pie_Slice_ID[1].succ! + Pie_Slice_ID.mutex.synchronize{ + @path = @id = Pie_Slice_ID.join(TkCore::INTERP._ip_id_) + Pie_Slice_ID[1].succ! + } + SliceID_TBL.mutex.synchronize{ + SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] + SliceID_TBL[@ppath][@id] = self + } if args[-1].kind_of?(Hash) keys = args.unshift @@ -209,22 +226,48 @@ end class Tk::Vu::NamedPieSlice def self.new(parent, name, *args) - if SliceID_TBL[parent.path] && SliceID_TBL[parent.path][name] - return SliceID_TBL[parent.path][name] - else - super(parent, name, *args) - end + obj = nil + SliceID_TBL.mutex.synchronize{ + if SliceID_TBL[parent.path] && SliceID_TBL[parent.path][name] + obj = SliceID_TBL[parent.path][name] + else + #super(parent, name, *args) + unless parent.kind_of?(Tk::Vu::Pie) + fail ArgumentError, "expect a Tk::Vu::Pie instance for 1st argument" + end + obj = self.allocate + obj.instance_eval{ + @parent = @pie = parent + @ppath = parent.path + @path = @id = name.to_s + SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] + SliceID_TBL[@ppath][@id] = self + } + end + } + obj.instance_eval{ + if args[-1].kind_of?(Hash) + keys = args.unshift + end + @pie.set(@id, *args) + configure(keys) + } + + obj end def initialize(parent, name, *args) + # dummy:: not called by 'new' method unless parent.kind_of?(Tk::Vu::Pie) fail ArgumentError, "expect a Tk::Vu::Pie instance for 1st argument" end @parent = @pie = parent @ppath = parent.path @path = @id = name.to_s - SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] - SliceID_TBL[@ppath][@id] = self + SliceID_TBL.mutex.synchronize{ + SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath] + SliceID_TBL[@ppath][@id] = self + } if args[-1].kind_of?(Hash) keys = args.unshift diff --git a/ext/tk/lib/tkextlib/vu/spinbox.rb b/ext/tk/lib/tkextlib/vu/spinbox.rb index b6499645a3..a7e40ea319 100644 --- a/ext/tk/lib/tkextlib/vu/spinbox.rb +++ b/ext/tk/lib/tkextlib/vu/spinbox.rb @@ -17,6 +17,6 @@ end module Tk module Vu - Spinbox = TkSpinbox + Spinbox = Tk::Spinbox end end diff --git a/ext/tk/lib/tkextlib/winico/winico.rb b/ext/tk/lib/tkextlib/winico/winico.rb index c53a3ff48c..30fb9682d5 100644 --- a/ext/tk/lib/tkextlib/winico/winico.rb +++ b/ext/tk/lib/tkextlib/winico/winico.rb @@ -34,10 +34,15 @@ end class Tk::Winico WinicoID_TBL = TkCore::INTERP.create_table - TkCore::INTERP.init_ip_env{ WinicoID_TBL.clear } + + TkCore::INTERP.init_ip_env{ + WinicoID_TBL.mutex.synchronize{ WinicoID_TBL.clear } + } def self.id2obj(id) - (WinicoID_TBL.key?(id))? WinicoID_TBL[id] : id + WinicoID_TBL.mutex.synchronize{ + (WinicoID_TBL.key?(id))? WinicoID_TBL[id] : id + } end def self.info @@ -81,7 +86,9 @@ class Tk::Winico "must be given proper information from where loading icons" end @path = @id - WinicoID_TBL[@id] = self + WinicoID_TBL.mutex.synchronize{ + WinicoID_TBL[@id] = self + } end def id @@ -96,7 +103,9 @@ class Tk::Winico def delete tk_call('winico', 'delete', @id) - WinicoID_TBL.delete(@id) + WinicoID_TBL.mutex.synchronize{ + WinicoID_TBL.delete(@id) + } self end alias destroy delete @@ -126,15 +135,37 @@ class Tk::Winico [ ?n, TkComm.method(:number) ], [ ?s, TkComm.method(:string) ], [ ?x, proc{|id| - if Tk::Winico::WinicoID_TBL.key?(id) - Tk::Winico::WinicoID_TBL[id] - else - Tk::Winico.new(nil, nil, id) - end + Tk::Winico::WinicoID_TBL.mutex.synchronize{ + if Tk::Winico::WinicoID_TBL.key?(id) + obj = Tk::Winico::WinicoID_TBL[id] + else + # Tk::Winico.new(nil, nil, id) + obj = Tk::Winico.allocate + obj.instance_eval{ @path = @id = id } + Tk::Winico::WinicoID_TBL[id] = obj + end + obj + } } ], nil ] + # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) ) + KEY_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String) + end + inf + } + + PROC_TBL.map!{|inf| + if inf.kind_of?(Array) + inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String) + end + inf + } + _setup_subst_table(KEY_TBL, PROC_TBL); def self.ret_val(val) diff --git a/ext/tk/sample/binstr_usage.rb b/ext/tk/sample/binstr_usage.rb index 91692856f9..be8399ba51 100644 --- a/ext/tk/sample/binstr_usage.rb +++ b/ext/tk/sample/binstr_usage.rb @@ -16,7 +16,7 @@ to avoid such troubles. Please see the source code of this sample. \ A Tk::BinaryString instance is used to create the image for the center button. EOM -ImgFile=['images','tcllogo.gif'].join(File::Separator) +ImgFile=[File.dirname(__FILE__), 'images','tcllogo.gif'].join(File::Separator) ph1 = TkPhotoImage.new(:file=>ImgFile) p ph1.configinfo @@ -28,12 +28,18 @@ ph2 = TkPhotoImage.new(:data=>b_str) p ph2.configinfo p ph2.data(:grayscale=>true) -ph3 = TkPhotoImage.new() -ph3.put(ph2.data(:grayscale=>true)) +ph3 = TkPhotoImage.new(:palette=>256) +ph3.put(ph2.data) + +ph4 = TkPhotoImage.new() +ph4.put(ph2.data(:grayscale=>true)) + +#p [b_str.encoding, b_str.rb_encoding] f = TkFrame.new.pack TkButton.new(:parent=>f, :image=>ph1, :command=>proc{exit}).pack(:side=>:left) TkButton.new(:parent=>f, :image=>ph2, :command=>proc{exit}).pack(:side=>:left) TkButton.new(:parent=>f, :image=>ph3, :command=>proc{exit}).pack(:side=>:left) +TkButton.new(:parent=>f, :image=>ph4, :command=>proc{exit}).pack(:side=>:left) Tk.mainloop diff --git a/ext/tk/sample/demos-en/arrow.rb b/ext/tk/sample/demos-en/arrow.rb index b62e1966eb..4a589a0892 100644 --- a/ext/tk/sample/demos-en/arrow.rb +++ b/ext/tk/sample/demos-en/arrow.rb @@ -77,11 +77,19 @@ def arrowSetup(c) 'arrow'=>'both', 'arrowshape'=>v.smallTips) TkcText.new(c, v.x2-5*v.b, tmp+5, 'text'=>v.b, 'anchor'=>'n') - TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') - TkcText.new(c, v.x1, 330, - 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]", 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') + if $tk_version =~ /^4.*/ + TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', + 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') + TkcText.new(c, v.x1, 330, + 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]",'anchor'=>'w', + 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') + else + TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', + 'font'=>'Helvetica 18') + TkcText.new(c, v.x1, 330, + 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]", + 'anchor'=>'w', 'font'=>'Helvetica 18') + end v.count += 1 end diff --git a/ext/tk/sample/demos-en/bind.rb b/ext/tk/sample/demos-en/bind.rb index b7e7122c57..5d6ec84edb 100644 --- a/ext/tk/sample/demos-en/bind.rb +++ b/ext/tk/sample/demos-en/bind.rb @@ -43,11 +43,11 @@ def tag_binding_for_bind_demo(tag, enter_style, leave_style) end # text -TkText.new($bind_demo){|t| +txt = TkText.new($bind_demo){|t| # setgrid 'true' - width 60 - height 24 + #width 60 + #height 24 font $font wrap 'word' TkScrollbar.new($bind_demo) {|s| @@ -120,3 +120,6 @@ TkText.new($bind_demo){|t| TkTextMarkInsert.new(t, '0.0') configure('state','disabled') } + +txt.width 60 +txt.width 24 diff --git a/ext/tk/sample/demos-en/ctext.rb b/ext/tk/sample/demos-en/ctext.rb index dbb5e32638..8c10880ed6 100644 --- a/ext/tk/sample/demos-en/ctext.rb +++ b/ext/tk/sample/demos-en/ctext.rb @@ -56,19 +56,28 @@ $ctext_canvas = TkCanvas.new($ctext_demo, 'relief'=>'flat', $ctext_canvas.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'both') # font -textFont = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' +if $tk_version =~ /^4.*/ + textFont = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' +else + textFont = 'Helvetica 24' +end # canvas TkcRectangle.new($ctext_canvas, 245, 195, 255, 205, 'outline'=>'black', 'fill'=>'red') +ctag_text_param = { + 'text'=>"This is just a string of text to demonstrate the text facilities of canvas widgets. Bindings have been been defined to support editing (see above).", + 'width'=>440, 'anchor'=>'n', 'justify'=>'left' +} +if $tk_version =~ /^4.*/ + ctag_text_param['font'] = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' +else + ctag_text_param['font'] = 'Helvetica 24' +end + $ctag_text = TkcTag.new($ctext_canvas) -$ctag_text.withtag(TkcText.new($ctext_canvas, 250, 200, - 'text'=>"This is just a string of text to demonstrate the text facilities of canvas widgets. Bindings have been been defined to support editing (see above).", - 'width'=>440, 'anchor'=>'n', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*', - 'kanjifont'=>'-*--24-*-jisx0208.1983-0', - 'justify'=>'left') ) +$ctag_text.withtag(TkcText.new($ctext_canvas, 250, 200, ctag_text_param)) $ctag_text.bind('1', proc{|x,y| textB1Press $ctext_canvas,x,y}, "%x %y") $ctag_text.bind('B1-Motion', proc{|x,y| textB1Move $ctext_canvas,x,y}, "%x %y") @@ -110,9 +119,14 @@ mkTextConfig $ctext_canvas, x+60, y+60, 'anchor', 'nw', color item = TkcRectangle.new($ctext_canvas, x+40, y+40, x+50, y+50, 'outline'=>'black', 'fill'=>'red') item.bind('1', proc{$ctag_text.configure 'anchor', 'center'}) -TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', 'anchor'=>'s', - 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', - 'fill'=>'brown') +if $tk_version =~ /^4.*/ + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', + 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', + 'anchor'=>'s', 'fill'=>'brown') +else + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', + 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown') +end # Lastly, create some items that allow the text's justification to be # changed. @@ -123,9 +137,14 @@ color = 'SeaGreen2' mkTextConfig $ctext_canvas, x, y, 'justify', 'left', color mkTextConfig $ctext_canvas, x+30, y, 'justify', 'center', color mkTextConfig $ctext_canvas, x+60, y, 'justify', 'right', color -TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', 'anchor'=>'s', - 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', - 'fill'=>'brown') +if $tk_version =~ /^4.*/ + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', + 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', + 'anchor'=>'s', 'fill'=>'brown') +else + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', + 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown') +end $ctext_canvas.itembind('config', 'Enter', proc{textEnter $ctext_canvas}) $ctext_canvas.itembind('config', 'Leave', diff --git a/ext/tk/sample/demos-en/entry3.rb b/ext/tk/sample/demos-en/entry3.rb index 415b45f86c..68f77a0d48 100644 --- a/ext/tk/sample/demos-en/entry3.rb +++ b/ext/tk/sample/demos-en/entry3.rb @@ -28,7 +28,7 @@ problem. The second only accepts strings with fewer than ten \ characters and sounds the bell when an attempt to go over the limit \ is made. The third accepts US phone numbers, mapping letters to \ their digit equivalent and sounding the bell on encountering an \ -illegal character or if trying to type over a character that is not \ +invalid character or if trying to type over a character that is not \ a digit. The fourth is a password field that accepts up to eight \ characters (silently ignoring further ones), and displaying them as \ asterisk characters. diff --git a/ext/tk/sample/demos-en/hello b/ext/tk/sample/demos-en/hello index f06eabe518..5e86ad7e3e 100644 --- a/ext/tk/sample/demos-en/hello +++ b/ext/tk/sample/demos-en/hello @@ -1,9 +1,9 @@ #!/usr/bin/env ruby require 'tk' -unless /^8\.[1-9]/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK - require 'tkencoding' -end +#unless /^8\.[1-9]/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK +# require 'tkencoding' +#end TkButton.new(nil, 'text'=>"Hello Ruby world!", diff --git a/ext/tk/sample/demos-en/hscale.rb b/ext/tk/sample/demos-en/hscale.rb index 14e395b61a..743c4b4852 100644 --- a/ext/tk/sample/demos-en/hscale.rb +++ b/ext/tk/sample/demos-en/hscale.rb @@ -62,7 +62,6 @@ TkFrame.new($hscale_demo) {|frame| scale.set 75 }.pack('side'=>'top', 'fill'=>'x') - def setWidth(w, width) width = width + 21 x2 = width - 30 @@ -72,3 +71,4 @@ def setWidth(w, width) w.coords 'poly',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15 w.coords 'line',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15 end + diff --git a/ext/tk/sample/demos-en/items.rb b/ext/tk/sample/demos-en/items.rb index 8ab7668a07..23191b59b9 100644 --- a/ext/tk/sample/demos-en/items.rb +++ b/ext/tk/sample/demos-en/items.rb @@ -94,8 +94,13 @@ TkcLine.new(cvs, '0c', '16c', '30c', '16c', 'width'=>2) TkcLine.new(cvs, '10c', '0c', '10c', '24c', 'width'=>2) TkcLine.new(cvs, '20c', '0c', '20c', '24c', 'width'=>2) -font1 = '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' -font2 = '-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*' +if $tk_version =~ /^4.*/ + font1 = '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' + font2 = '-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*' +else + font1 = 'Helvetica 12' + font2 = 'Helvetica 24 bold' +end if TkWinfo.depth($root).to_i > 1 blue = 'DeepSkyBlue3' red = 'red' diff --git a/ext/tk/sample/demos-en/patch_1.1c1 b/ext/tk/sample/demos-en/patch_1.1c1 deleted file mode 100644 index d3952e71eb..0000000000 --- a/ext/tk/sample/demos-en/patch_1.1c1 +++ /dev/null @@ -1,93 +0,0 @@ ---- /usr/src/ruby-1.1c1/lib/tkcanvas.rb Tue Jul 21 18:18:02 1998 -+++ tkcanvas.rb Fri Jul 24 20:38:24 1998 -@@ -310,7 +310,7 @@ - || key == 'latinfont' || key == 'asciifont' ) - tagfont_configure(tagid(tagOrId), {key=>value}) - else -- tk_call 'itemconfigure', tagid(tagOrId), "-#{key}", value -+ tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value - end - end - end ---- /usr/src/ruby-1.1c1/lib/tkfont.rb Fri Jul 17 23:43:28 1998 -+++ tkfont.rb Fri Jul 24 17:46:22 1998 -@@ -42,7 +42,7 @@ - r | [] - - when /^8\.*/ -- list(tk_call('font', 'names')) -+ tk_split_simplelist(tk_call('font', 'names')) - - end - end -@@ -89,10 +89,14 @@ - if fnt == [] - TkFont.new(nil, nil).call_font_configure(path, *(args + [{}])) - else -- compound = Hash[*list(tk_call('font', 'configure', -- fnt))].collect{|key,value| -- [key[1..-1], value] -- }.assoc('compound')[1] -+ begin -+ compound = Hash[*list(tk_call('font', 'configure', -+ fnt))].collect{|key,value| -+ [key[1..-1], value] -+ }.assoc('compound')[1] -+ rescue -+ compound = [] -+ end - if compound == [] - TkFont.new(fnt, DEFAULT_KANJI_FONT_NAME) \ - .call_font_configure(path, *(args + [{}])) -@@ -156,14 +160,19 @@ - elsif font.kind_of? Array - finfo = {} - finfo['family'] = font[0].to_s -- if font[1] && font[1] != '0' && font[1] =~ /^(|\+|-)([0-9]+)$/ -- if $1 == '-' -- finfo['pixels'] = font[1].to_s -+ if font[1] -+ fsize = font[1].to_s -+ if fsize != '0' && fsize =~ /^(|\+|-)([0-9]+)$/ -+ if $1 == '-' -+ finfo['pixels'] = $2 -+ else -+ finfo['points'] = $2 -+ end - else -- finfo['points'] = font[1].to_s -+ finfo['points'] = '13' - end - end -- finfo[2..-1].each{|style| -+ font[2..-1].each{|style| - case (style) - when 'normal' - finfo['weight'] = style -@@ -199,16 +208,19 @@ - elsif font.kind_of? Array - finfo = {} - finfo['family'] = font[0].to_s -- if font[1] && font[1] != '0' && font[1] =~ /^(|\+|-)([0-9]+)$/ -- if $1 == '-' -- finfo['pixels'] = $2 -+ if font[1] -+ fsize = font[1].to_s -+ if fsize != '0' && fsize =~ /^(|\+|-)([0-9]+)$/ -+ if $1 == '-' -+ finfo['pixels'] = $2 -+ else -+ finfo['points'] = $2 -+ end - else -- finfo['points'] = $2 -+ finfo['points'] = '13' - end -- else -- finfo['points'] = '13' - end -- finfo[2..-1].each{|style| -+ font[2..-1].each{|style| - case (style) - when 'normal' - finfo['weight'] = style diff --git a/ext/tk/sample/demos-en/pendulum.rb b/ext/tk/sample/demos-en/pendulum.rb index 36bb44edec..a3498d67cf 100644 --- a/ext/tk/sample/demos-en/pendulum.rb +++ b/ext/tk/sample/demos-en/pendulum.rb @@ -49,9 +49,11 @@ TkFrame.new($pendulum_demo) {|frame| class PendulumAnimationDemo def initialize(frame) # Create some structural widgets - pane = TkPanedWindow.new(frame).pack(:fill=>:both, :expand=>true) - pane.add(@lf1 = TkLabelFrame.new(pane, :text=>'Pendulum Simulation')) - pane.add(@lf2 = TkLabelFrame.new(pane, :text=>'Phase Space')) + @pane = TkPanedWindow.new(frame).pack(:fill=>:both, :expand=>true) +# @pane.add(@lf1 = TkLabelFrame.new(@pane, :text=>'Pendulum Simulation')) +# @pane.add(@lf2 = TkLabelFrame.new(@pane, :text=>'Phase Space')) + @lf1 = TkLabelFrame.new(@pane, :text=>'Pendulum Simulation') + @lf2 = TkLabelFrame.new(@pane, :text=>'Phase Space') # Create the canvas containing the graphical representation of the # simulated system. @@ -99,23 +101,24 @@ class PendulumAnimationDemo @dTheta = 0.0 @length = 150 - # init display - showPendulum - # animation loop @timer = TkTimer.new(15){ repeat } # binding @c.bindtags_unshift(btag = TkBindTag.new) btag.bind('Destroy'){ @timer.stop } - btag.bind('1', proc{|x, y| @timer.stop; showPendulum(x, y)}, '%x %y') - btag.bind('B1-Motion', proc{|x, y| showPendulum(x, y)}, '%x %y') + btag.bind('1', proc{|x, y| @timer.stop; showPendulum(x.to_i, y.to_i)}, + '%x %y') + btag.bind('B1-Motion', proc{|x, y| showPendulum(x.to_i, y.to_i)}, '%x %y') btag.bind('ButtonRelease-1', - proc{|x, y| showPendulum(x, y); @timer.start }, '%x %y') + proc{|x, y| showPendulum(x.to_i, y.to_i); @timer.start }, + '%x %y') - btag.bind('Configure', proc{|w| @plate.coords(0, 25, w, 25)}, '%w') + btag.bind('Configure', proc{|w| @plate.coords(0, 25, w.to_i, 25)}, '%w') @k.bind('Configure', proc{|h, w| + h = h.to_i + w = w.to_i @psh = h/2; @psw = w/2 @x_axis.coords(2, @psh, w-2, @psh) @@ -124,6 +127,14 @@ class PendulumAnimationDemo @label_dtheta.coords(w-6, @psh+4) }, '%h %w') + # add + Tk.update + @pane.add(@lf1) + @pane.add(@lf2) + + # init display + showPendulum + # animation start @timer.start(500) end @@ -154,6 +165,10 @@ class PendulumAnimationDemo # rate at which the angle is changing (the first derivative with # respect to time.) def showPhase + unless @psw && @psh + @psw = @k.width/2 + @psh = @k.height/2 + end @points << @theta + @psw << -20*@dTheta + @psh if @points.length > 100 @points = @points[-100..-1] diff --git a/ext/tk/sample/demos-en/rolodex-j b/ext/tk/sample/demos-en/rolodex-j deleted file mode 100644 index 27e2bc9da0..0000000000 --- a/ext/tk/sample/demos-en/rolodex-j +++ /dev/null @@ -1,323 +0,0 @@ -#!/usr/bin/env ruby -# -# rolodex -- -# ¤³¤Î¥¹¥¯¥ê¥×¥È¤Ï Tom LaStrange ¤Î rolodex ¤Î°ìÉô¤Ç¤¹¡£ -# -# Copyright (C) 1998 by Takaaki Tateishi -# Time-stamp: "03/08/02 14:02:04 nagai" -# - -require "tk" - -Tk.encoding = "euc-jp" -$font = TkFont.new('k14') - -def show_help(topic,x=0,y=0) - if( topic.is_a?(TkWindow) ) - w = TkWinfo.containing(x,y) - if( w.is_a?(TkWindow) ) - if( TkWinfo.exist?(w) ) - topic = w - end - end - end - - if( $helpTopics.include?(topic) ) - msg = $helpTopics[topic] - else - msg = "¤³¤Î¥È¥Ô¥Ã¥¯¤Ë¤Ä¤¤¤Æ¤Î¥Ø¥ë¥×¤Ï¤Þ¤À»ÈÍѤǤ­¤Þ¤»¤ó" - end - TkDialog.new("title"=>"Rolodex Help", - "message"=>"¡Ö#{topic}¡×\n\n#{msg}", - "font"=>$font, - "default_button"=>0, - "buttons"=>["OK"]) -end - -def fillCard - clearAction - $root.frame.entry[1].insert(0, "ΩÀÐ ¹§¾´") - $root.frame.entry[2].insert(0, "923-1292 ÀÐÀ") - $root.frame.entry[3].insert(0, "ä¸ýÄ® °°Âæ 1-1") - $root.frame.entry[4].insert(0, "ËÌΦÀèü²Ê³Øµ»½ÑÂç³Ø±¡Âç³Ø") - $root.frame.entry[5].insert(0,"private") - $root.frame.entry[6].insert(0,"***-***-****") - $root.frame.entry[7].insert(0,"***-***-****") -end - -def addAction - for i in 1..7 - STDERR.print format("%-12s %s\n", - RolodexFrame::LABEL[i], - $root.frame.entry[i].value) - end -end - -def clearAction - for i in 1..7 - $root.frame.entry[i].delete(0,"end") - end -end - -def fileAction - TkDialog.new("title"=>"File Selection", - "message"=>"¤³¤ì¤Ï¥Õ¥¡¥¤¥ëÁªÂò¥À¥¤¥¢¥í¥°¤Î¥À¥ß¡¼¤Ç¤¹¡£\n", - "font"=>$font, - "default_button"=>0, - "buttons"=>["OK"]) - STDERR.print "dummy file name\n" -end - -def deleteAction - result = TkDialog.new("title"=>"Confirm Action", - "message"=>"¤è¤í¤·¤¤¤Ç¤¹¤«¡©", - "font"=>$font, - "default_button"=>0, - "buttons"=>["¥­¥ã¥ó¥»¥ë"]) - if( result.value == 0 ) - clearAction - end -end - - -class RolodexFrame < TkFrame - attr_reader :entry, :label - - LABEL = ["","̾Á°:","½»½ê","","","ÅÅÏÃ(¼«Âð):","ÅÅÏÃ(²ñ¼Ò):","Fax:"] - - def initialize(parent=nil,keys=nil) - super(parent,keys) - self["relief"] = "flat" - @i = [] - @label = [] - @entry = [] - for i in 1..7 - @i[i] = TkFrame.new(self) - @i[i].pack("side"=>"top", - "pady"=>2, - "anchor"=>"e") - @label[i] = TkLabel.new(@i[i], - "text"=>LABEL[i], - "anchor"=>"e", - "font" => $font) - @entry[i] = TkEntry.new(@i[i], - "width"=>30, - "relief"=>"sunken", - "font" => $font) - @entry[i].pack("side"=>"right") - @label[i].pack("side"=>"right") - end - end -end - -class RolodexButtons < TkFrame - attr_reader :clear, :add, :search, :delete - - def initialize(parent,keys=nil) - super(parent,keys) - @clear = TkButton.new(self, - "text" => "¥¯¥ê¥¢¡¼", - "font" => $font) - @add = TkButton.new(self, - "text" => "ÄɲÃ", - "font" => $font) - @search = TkButton.new(self, - "text" => "¸¡º÷", - "font" => $font) - @delete = TkButton.new(self, - "text" => "¾Ãµî", - "font" => $font) - for w in [@clear,@add,@search,@delete] - w.pack("side"=>"left", "padx"=>2) - end - end -end - -class RolodexMenuFrame < TkFrame - attr_reader :file_menu, :help_menu, :file, :help - - def initialize(parent,keys=nil) - super(parent,keys) - configure("relief"=>"raised", - "borderwidth"=>1) - - @file = TkMenubutton.new(self, - "text"=> "¥Õ¥¡¥¤¥ë", - "font"=> $font, - "underline"=>0) - @file_menu = TkMenu.new(@file) - @file_menu.add("command", - "label" => "Æɤ߹þ¤ß ...", - "font" => $font, - "command" => proc{fileAction}, - "underline" => 0) - @file_menu.add("command", - "label" => "½ªÎ»", - "font" => $font, - "command" => proc{$root.destroy}, - "underline" => 0) - @file.menu(@file_menu) - @file.pack("side"=>"left") - - @help = TkMenubutton.new(self, - "text"=> "¥Ø¥ë¥×", - "font"=> $font, - "underline"=>0) - @help_menu = TkMenu.new(@help) - @help_menu.add("command", - "label"=> "¥³¥ó¥Æ¥­¥¹¥È¤Ë¤Ä¤¤¤Æ", - "font" => $font, - "command"=>proc{show_help("¥³¥ó¥Æ¥­¥¹¥È")}, - "underline"=>3) - @help_menu.add("command", - "label"=> "¥Ø¥ë¥×¤Ë¤Ä¤¤¤Æ", - "font" => $font, - "command"=>proc{show_help("¥Ø¥ë¥×")}, - "underline"=>3) - @help_menu.add("command", - "label"=> "¥¦¥£¥ó¥É¥¦¤Ë¤Ä¤¤¤Æ", - "font" => $font, - "command"=>proc{show_help("¥¦¥£¥ó¥É¥¦")}, - "underline"=>3) - @help_menu.add("command", - "label"=> "¥­¡¼Áàºî¤Ë¤Ä¤¤¤Æ", - "font" => $font, - "command"=>proc{show_help("¥­¡¼Áàºî")}, - "underline"=>3) - @help_menu.add("command", - "label"=> "¥Ð¡¼¥¸¥ç¥ó¾ðÊó", - "font" => $font, - "command"=>proc{show_help("¥Ð¡¼¥¸¥ç¥ó¾ðÊó")}, - "underline"=>3) - @help.menu(@help_menu) - @help.pack("side"=>"right") - end -end - -class Rolodex < TkRoot - attr_reader :frame, :buttons, :menu - - def initialize(*args) - super(*args) - @frame = RolodexFrame.new(self) - @frame.pack("side"=>"top", - "fill"=>"y", - "anchor"=>"center") - @buttons = RolodexButtons.new(self) - @buttons.pack("side"=>"bottom", - "pady"=>2, - "anchor"=>"center") - @menu = RolodexMenuFrame.new(self) - @menu.pack("before"=>@frame, - "side"=>"top", - "fill"=>"x") - end -end - -$root = Rolodex.new - -$root.buttons.delete.configure("command"=>proc{deleteAction}) -$root.buttons.add.configure("command"=>proc{addAction}) -$root.buttons.clear.configure("command"=>proc{clearAction}) -$root.buttons.search.configure("command"=>proc{addAction; fillCard}) - -$root.buttons.clear.configure("text"=> "¥¯¥ê¥¢¡¼ Ctrl+C", "font" => $font) -$root.bind("Control-c",proc{clearAction}) - -$root.buttons.add.configure("text"=> "Äɲà Ctrl+A", "font" => $font) -$root.bind("Control-a",proc{addAction}) - -$root.buttons.search.configure("text"=> "¸¡º÷ Ctrl+S", "font" => $font) -$root.bind("Control-s",proc{addAction; fillCard}) - -$root.buttons.delete.configure("text"=> "¾Ãµî Ctrl+D", "font" => $font) -$root.bind("Control-d",proc{deleteAction}) - -$root.menu.file_menu.entryconfigure(1, "accel"=>"Ctrl+F") -$root.bind("Control-f",proc{fileAction}) - -$root.menu.file_menu.entryconfigure(2, "accel"=>"Ctrl+Q") -$root.bind("Control-q",proc{$root.destroy}) - -$root.frame.entry[1].focus - -$root.bind("Any-F1", - proc{|event| show_help(event.widget, event.x_root, event.y_root)}) -$root.bind("Any-Help", - proc{|event| show_help(event.widget, event.x_root, event.y_root)}) - - -$helpTopics = {} - -$helpTopics[$root.menu.file] = <true, 'wrap'=>'word') {|t| pack('side'=>'right', 'fill'=>'y') } pack('expand'=>'yes', 'fill'=>'both') -} +} # Set up display styles for text highlighting. @@ -173,8 +173,13 @@ type a string in the lower entry and type or click on \ \"Load File\". This will cause all of the instances of the string to \ be tagged with the tag \"search\", and it will arrange for the tag\'s \ display attributes to change to make all of the strings blink.") +$search_text.insert('end', "\ +The current directory to load a file is \"#{Dir.pwd}\".\ +") $search_text.set_insert '0.0' $search_fileName.value = '' $search_searchString.value = '' +$search_text.width = 60 +$search_text.height = 20 diff --git a/ext/tk/sample/demos-en/style.rb b/ext/tk/sample/demos-en/style.rb index 5ed11aa459..8606893c9b 100644 --- a/ext/tk/sample/demos-en/style.rb +++ b/ext/tk/sample/demos-en/style.rb @@ -40,9 +40,10 @@ TkFrame.new($style_demo) {|frame| TkText.new($style_demo){|t| # setgrid 'true' - width 70 - height 32 + #width 70 + #height 32 wrap 'word' + font $font TkScrollbar.new($style_demo) {|s| pack('side'=>'right', 'fill'=>'y') command proc{|*args| t.yview(*args)} @@ -51,11 +52,20 @@ TkText.new($style_demo){|t| pack('expand'=>'yes', 'fill'=>'both') # - style_tag_bold = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-O-Normal--*-120-*-*-*-*-*-*') - style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font) + family = 'Courier' + + if $tk_version =~ /^4.*/ + style_tag_bold = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-O-Normal--*-120-*-*-*-*-*-*') + style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font) style_tag_verybig = TkTextTag.new(t, 'font'=>'-*-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*') -# style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font) + # style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font) style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*') + else + style_tag_bold = TkTextTag.new(t, 'font'=>[family, 12, :bold, :italic]) + style_tag_big = TkTextTag.new(t, 'font'=>[family, 14, :bold]) + style_tag_verybig = TkTextTag.new(t, 'font'=>['Helvetica', 24, :bold]) + style_tag_small = TkTextTag.new(t, 'font'=>['Times 8 bold']) + end ### # case($tk_version) # when /^4.*/ @@ -109,8 +119,13 @@ TkText.new($style_demo){|t| style_tag_overstrike = TkTextTag.new(t, 'overstrike'=>'on') style_tag_right = TkTextTag.new(t, 'justify'=>'right') style_tag_center = TkTextTag.new(t, 'justify'=>'center') - style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') - style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') + if $tk_version =~ /^4.*/ + style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') + style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') + else + style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>[family, 10]) + style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>[family, 10]) + end style_tag_margins = TkTextTag.new(t, 'lmargin1'=>'12m', 'lmargin2'=>'6m', 'rmargin'=>'10m') style_tag_spacing = TkTextTag.new(t, 'spacing1'=>'10p', 'spacing2'=>'2p', @@ -132,7 +147,8 @@ available display styles are: insert('end', " You can choose any X font, ") insert('end', "large", style_tag_verybig) insert('end', " or ") - insert('end', "small.\n") + insert('end', "small", style_tag_small) + insert('end', ".\n") insert('end', "\n2. Color.", style_tag_big) insert('end', " You can change either the ") insert('end', "background", style_tag_color1) @@ -209,3 +225,5 @@ available display styles are: } +txt.width 70 +txt.height 32 diff --git a/ext/tk/sample/demos-en/textpeer.rb b/ext/tk/sample/demos-en/textpeer.rb new file mode 100644 index 0000000000..d98ef170b4 --- /dev/null +++ b/ext/tk/sample/demos-en/textpeer.rb @@ -0,0 +1,72 @@ +# +# text widget peering demo (called by 'widget') +# +# based on Tcl/Tk8.5.0 widget demos + +if defined?($textpeer_demo) && $textpeer_demo + $textpeer_demo.destroy + $textpeer_demo = nil +end + +# demo toplevel widget +$textpeer_demo = TkToplevel.new {|w| + title("Text Wdget Peering Demonstration") + iconname("textpeer") + positionWindow(w) +} + +count = [0] + +## Define a widget that we peer from; it won't ever actually be shown though +first = TkText.new($textpeer_demo, :widgetname=>"text#{count[0] += 1}") +first.insert :end,"This is a coupled pair of text widgets; they are peers to " +first.insert :end,"each other. They have the same underlying data model, but " +first.insert :end,"can show different locations, have different current edit " +first.insert :end,"locations, and have different selections. You can also " +first.insert :end,"create additional peers of any of these text widgets using " +first.insert :end,"the Make Peer button beside the text widget to clone, and " +first.insert :end,"delete a particular peer widget using the Delete Peer " +first.insert :end,"button." + +## Procedures to make and kill clones; most of this is just so that the demo +## looks nice... +def makeClone(count, win, txt) + cnt = (count[0] += 1) + peer = TkText::Peer.new(txt, win, :widgetname=>"text#{cnt}") + sbar = TkScrollbar.new(win, :widgetname=>"sb#{cnt}") + peer.yscrollbar sbar + b1 = TkButton.new(win, :widgetname=>"clone#{cnt}", :text=>'Make Peer', + :command=>proc{makeClone(count, win, peer)}) + b2 = TkButton.new(win, :widgetname=>"kill#{cnt}", :text=>'Delete Peer', + :command=>proc{killClone(win, cnt)}) + row = cnt * 2 + TkGrid.configure(peer, sbar, b1, :sticky=>'nsew', :row=>row) + TkGrid.configure('^', '^', b2, :sticky=>'nsew', :row=>(row+=1)) + TkGrid.configure(b1, b2, :sticky=>'new') + TkGrid.rowconfigure(win, b2, :weight=>1) +end + +def killClone(win, cnt) + Tk.destroy("#{win.path}.text#{cnt}", "#{win.path}.sb#{cnt}", + "#{win.path}.clone#{cnt}", "#{win.path}.kill#{cnt}") +end + +## Now set up the GUI +makeClone(count, $textpeer_demo, first) +makeClone(count, $textpeer_demo, first) +first.destroy + +## See Code / Dismiss buttons +TkFrame.new($textpeer_demo){|f| + TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{ + $textpeer_demo.destroy + $textpeer_demo = nil + }).pack(:side=>:left, :expand=>true) + + TkButton.new(f, :text=>'See Code', :width=>15, :command=>proc{ + showCode 'textpeer' + }).pack(:side=>:left, :expand=>true) + + TkGrid.configure(f, '-', '-', :sticky=>'ew', :row=>5000) +} +TkGrid.columnconfigure($textpeer_demo, 0, :weight=>1) diff --git a/ext/tk/sample/demos-en/twind.rb b/ext/tk/sample/demos-en/twind.rb index 24a4bcf706..f29e49f35a 100644 --- a/ext/tk/sample/demos-en/twind.rb +++ b/ext/tk/sample/demos-en/twind.rb @@ -206,7 +206,11 @@ def textWindPlot (t) cursor 'top_left_arrow' } - font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' + if $tk_version =~ /^4.*/ + font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' + else + font = 'Helvetica 18' + end TkcLine.new($twind_plot, 100, 250, 400, 250, 'width'=>2) TkcLine.new($twind_plot, 100, 250, 100, 50, 'width'=>2) diff --git a/ext/tk/sample/demos-en/vscale.rb b/ext/tk/sample/demos-en/vscale.rb index 636b85813b..c0170467d5 100644 --- a/ext/tk/sample/demos-en/vscale.rb +++ b/ext/tk/sample/demos-en/vscale.rb @@ -66,7 +66,6 @@ TkFrame.new($vscale_demo) {|frame| scale.set 75 }.pack - def setHeight(w, height) height = height + 21 y2 = height - 30 diff --git a/ext/tk/sample/demos-en/widget b/ext/tk/sample/demos-en/widget index adf8cb76ed..391d8532b6 100644 --- a/ext/tk/sample/demos-en/widget +++ b/ext/tk/sample/demos-en/widget @@ -21,7 +21,8 @@ require 'tk' #---------------------------------------------------------------- # widget demo directory -$demo_dir = File.dirname($0) +# $demo_dir = File.dirname($0) +$demo_dir = File.dirname(__FILE__) # root $root = TkRoot.new{title "Ruby/Tk Widget Demonstration"} @@ -164,12 +165,17 @@ else textFrame.pack('expand'=>'yes', 'fill'=>'both') statusBar = TkFrame.new($root) {|f| + if $tk_version =~ /^4.*/ + statusfont = '-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' + else + statusfont = 'Helvetica 10' + end $statusBarLabel = \ TkLabel.new(f, 'text'=>" ", 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') \ + 'font'=>statusfont) \ .pack('side'=>'left', 'padx'=>2, 'expand'=>'yes', 'fill'=>'both') TkLabel.new(f, 'width'=>8, 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') \ + 'font'=>statusfont) \ .pack('side'=>'left', 'padx'=>2) }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>2) end @@ -178,7 +184,11 @@ end # section titles and demo descriptions. Also define the bindings for # tags. -tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*') +if $tk_version =~ /^4.*/ + tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*') +else + tag_title = TkTextTag.new(txt, 'font'=>'Helvetica 18 bold') +end # We put some "space" characters to the left and right of each demo description # so that the descriptions are highlighted only when the mouse cursor @@ -331,6 +341,8 @@ txt.insert('end', "5. A text widget with embedded windows. (if supported)\n", ta txt.insert('end', " \n ", tag_demospace) txt.insert('end', "6. A search tool built with a text widget.\n", tag_demo, "demo-search") txt.insert('end', " \n ", tag_demospace) +txt.insert('end', "7. Peering text widgets. (if supported)\n", tag_demo, "demo-textpeer") +txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") txt.insert('end', "Canvases\n", tag_title) @@ -445,7 +457,11 @@ def showVars1(parent, *args) text "Variable values:" width 20 anchor 'center' - font '-Adobe-helvetica-medium-r-normal--*-180-*-*-*-*-*-*' + if $tk_version =~ /^4.*/ + font '-Adobe-helvetica-medium-r-normal--*-180-*-*-*-*-*-*' + else + font 'Helvetica 14' + end }.pack('side'=>'top', 'fill'=>'x') len = 1 args.each{|vnam,vbody| @@ -592,7 +608,9 @@ end private :_null_binding def eval_samplecode(code) - Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } }.run + #eval(code) + #_null_binding.pseudo_toplevel_eval{ eval(code) } + Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } } Tk.update end @@ -896,7 +914,7 @@ end # def aboutBox Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo', - 'message'=>"Ruby/Tk widget demonstration Ver.1.6.2-en\n\n" + + 'message'=>"Ruby/Tk widget demonstration Ver.1.6.3-en\n\n" + "based on demos of Tk8.1 -- 8.5 " + "( Copyright:: " + "(c) 1996-1997 Sun Microsystems, Inc. / " + diff --git a/ext/tk/sample/demos-jp/anilabel.rb b/ext/tk/sample/demos-jp/anilabel.rb index 97781fbe77..c6e5c7385b 100644 --- a/ext/tk/sample/demos-jp/anilabel.rb +++ b/ext/tk/sample/demos-jp/anilabel.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # animated label widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/aniwave.rb b/ext/tk/sample/demos-jp/aniwave.rb index 81e2d76b30..5f94add111 100644 --- a/ext/tk/sample/demos-jp/aniwave.rb +++ b/ext/tk/sample/demos-jp/aniwave.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # animated wave demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/arrow.rb b/ext/tk/sample/demos-jp/arrow.rb index 477a0abf6f..b2c1067027 100644 --- a/ext/tk/sample/demos-jp/arrow.rb +++ b/ext/tk/sample/demos-jp/arrow.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # arrowhead widget demo (called by 'widget') # @@ -73,11 +74,19 @@ def arrowSetup(c) 'arrow'=>'both', 'arrowshape'=>v.smallTips) TkcText.new(c, v.x2-5*v.b, tmp+5, 'text'=>v.b, 'anchor'=>'n') - TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') - TkcText.new(c, v.x1, 330, - 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]", 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') + if $tk_version =~ /^4.*/ + TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', + 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') + TkcText.new(c, v.x1, 330, + 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]",'anchor'=>'w', + 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*') + else + TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w', + 'font'=>'Helvetica 18') + TkcText.new(c, v.x1, 330, + 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]", + 'anchor'=>'w', 'font'=>'Helvetica 18') + end v.count += 1 end diff --git a/ext/tk/sample/demos-jp/bind.rb b/ext/tk/sample/demos-jp/bind.rb index 4f9235cfa6..3b6f6242c2 100644 --- a/ext/tk/sample/demos-jp/bind.rb +++ b/ext/tk/sample/demos-jp/bind.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # text (tag bindings) widget demo (called by 'widget') # @@ -40,11 +41,11 @@ def tag_binding_for_bind_demo(tag, enter_style, leave_style) end # text À¸À® -TkText.new($bind_demo){|t| +txt = TkText.new($bind_demo){|t| # À¸À® setgrid 'true' - width 60 - height 24 + #width 60 + #height 24 font $font wrap 'word' TkScrollbar.new($bind_demo) {|s| @@ -117,3 +118,6 @@ TkText.new($bind_demo){|t| TkTextMarkInsert.new(t, '0.0') configure('state','disabled') } + +txt.width 60 +txt.width 24 diff --git a/ext/tk/sample/demos-jp/bitmap.rb b/ext/tk/sample/demos-jp/bitmap.rb index b71c67d3fd..4594892c81 100644 --- a/ext/tk/sample/demos-jp/bitmap.rb +++ b/ext/tk/sample/demos-jp/bitmap.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # bitmap widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/button.rb b/ext/tk/sample/demos-jp/button.rb index 20f8cae299..7e9457f5b4 100644 --- a/ext/tk/sample/demos-jp/button.rb +++ b/ext/tk/sample/demos-jp/button.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # button widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/check.rb b/ext/tk/sample/demos-jp/check.rb index be675b9042..7545df80fa 100644 --- a/ext/tk/sample/demos-jp/check.rb +++ b/ext/tk/sample/demos-jp/check.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # checkbutton widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/check2.rb b/ext/tk/sample/demos-jp/check2.rb index f681a4d684..90c6dd736f 100644 --- a/ext/tk/sample/demos-jp/check2.rb +++ b/ext/tk/sample/demos-jp/check2.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # checkbutton widget demo2 (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/clrpick.rb b/ext/tk/sample/demos-jp/clrpick.rb index de8cd80fcd..d81ecebc83 100644 --- a/ext/tk/sample/demos-jp/clrpick.rb +++ b/ext/tk/sample/demos-jp/clrpick.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # widget demo prompts the user to select a color (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/colors.rb b/ext/tk/sample/demos-jp/colors.rb index c6128f9c00..68b40e69f0 100644 --- a/ext/tk/sample/demos-jp/colors.rb +++ b/ext/tk/sample/demos-jp/colors.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # listbox widget demo 'colors' (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/cscroll.rb b/ext/tk/sample/demos-jp/cscroll.rb index 0d6db69af6..0be26133c5 100644 --- a/ext/tk/sample/demos-jp/cscroll.rb +++ b/ext/tk/sample/demos-jp/cscroll.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # simple scrollable canvas widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/ctext.rb b/ext/tk/sample/demos-jp/ctext.rb index 66e1fe8107..f5daf7ca05 100644 --- a/ext/tk/sample/demos-jp/ctext.rb +++ b/ext/tk/sample/demos-jp/ctext.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # Canvas Text widget demo (called by 'widget') # @@ -52,19 +53,28 @@ $ctext_canvas = TkCanvas.new($ctext_demo, 'relief'=>'flat', $ctext_canvas.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'both') # font ÀßÄê -textFont = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' +if $tk_version =~ /^4.*/ + textFont = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' +else + textFont = 'Helvetica 24' +end # canvas ÀßÄê TkcRectangle.new($ctext_canvas, 245, 195, 255, 205, 'outline'=>'black', 'fill'=>'red') +ctag_text_param = { + 'text'=>"¤³¤ì¤Ï¥­¥ã¥ó¥Ð¥¹widget¤Î¥Æ¥­¥¹¥Èµ¡Ç½¤ò¥Ç¥â¤¹¤ë¤¿¤á¤Îʸ»úÎó¤Ç¤¹¡£\n¾å¤Ç½Ò¤Ù¤¿¤è¤¦¤ÊÊÔ½¸¤ò²Äǽ¤È¤¹¤ë¤¿¤á¤Î¥Ð¥¤¥ó¥Ç¥£¥ó¥°¤ò»Ü¤·¤Æ¤¤¤Þ¤¹¡£", + 'width'=>440, 'anchor'=>'n', 'justify'=>'left' +} +if $tk_version =~ /^4.*/ + ctag_text_param['font'] = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*' + ctag_text_param['kanjifont'] = '-*-r-*--24-*-jisx0208.1983-0' +else + ctag_text_param['font'] = 'Helvetica 24' +end $ctag_text = TkcTag.new($ctext_canvas) -$ctag_text.withtag(TkcText.new($ctext_canvas, 250, 200, - 'text'=>"¤³¤ì¤Ï¥­¥ã¥ó¥Ð¥¹widget¤Î¥Æ¥­¥¹¥Èµ¡Ç½¤ò¥Ç¥â¤¹¤ë¤¿¤á¤Îʸ»úÎó¤Ç¤¹¡£\n¾å¤Ç½Ò¤Ù¤¿¤è¤¦¤ÊÊÔ½¸¤ò²Äǽ¤È¤¹¤ë¤¿¤á¤Î¥Ð¥¤¥ó¥Ç¥£¥ó¥°¤ò»Ü¤·¤Æ¤¤¤Þ¤¹¡£", - 'width'=>440, 'anchor'=>'n', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*', - 'kanjifont'=>'-*-r-*--24-*-jisx0208.1983-0', - 'justify'=>'left') ) +$ctag_text.withtag(TkcText.new($ctext_canvas, 250, 200, ctag_text_param)) $ctag_text.bind('1', proc{|x,y| textB1Press $ctext_canvas,x,y}, "%x %y") $ctag_text.bind('B1-Motion', proc{|x,y| textB1Move $ctext_canvas,x,y}, "%x %y") @@ -106,9 +116,14 @@ mkTextConfig $ctext_canvas, x+60, y+60, 'anchor', 'nw', color item = TkcRectangle.new($ctext_canvas, x+40, y+40, x+50, y+50, 'outline'=>'black', 'fill'=>'red') item.bind('1', proc{$ctag_text.configure 'anchor', 'center'}) -TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', 'anchor'=>'s', - 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', - 'fill'=>'brown') +if $tk_version =~ /^4.*/ + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', + 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', + 'anchor'=>'s', 'fill'=>'brown') +else + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', + 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown') +end # Lastly, create some items that allow the text's justification to be # changed. @@ -119,9 +134,14 @@ color = 'SeaGreen2' mkTextConfig $ctext_canvas, x, y, 'justify', 'left', color mkTextConfig $ctext_canvas, x+30, y, 'justify', 'center', color mkTextConfig $ctext_canvas, x+60, y, 'justify', 'right', color -TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', 'anchor'=>'s', - 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', - 'fill'=>'brown') +if $tk_version =~ /^4.*/ + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', + 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*', + 'anchor'=>'s', 'fill'=>'brown') +else + TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', + 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown') +end $ctext_canvas.itembind('config', 'Enter', proc{textEnter $ctext_canvas}) $ctext_canvas.itembind('config', 'Leave', diff --git a/ext/tk/sample/demos-jp/dialog1.rb b/ext/tk/sample/demos-jp/dialog1.rb index 0d6181bfc6..07e50306ab 100644 --- a/ext/tk/sample/demos-jp/dialog1.rb +++ b/ext/tk/sample/demos-jp/dialog1.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # a dialog box with a local grab (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/dialog2.rb b/ext/tk/sample/demos-jp/dialog2.rb index a934378dda..f747f8d6a8 100644 --- a/ext/tk/sample/demos-jp/dialog2.rb +++ b/ext/tk/sample/demos-jp/dialog2.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # a dialog box with a global grab (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/entry1.rb b/ext/tk/sample/demos-jp/entry1.rb index edf3b5f71d..d794282284 100644 --- a/ext/tk/sample/demos-jp/entry1.rb +++ b/ext/tk/sample/demos-jp/entry1.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # entry (no scrollbars) widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/entry2.rb b/ext/tk/sample/demos-jp/entry2.rb index 7d5740e663..528ad6dec4 100644 --- a/ext/tk/sample/demos-jp/entry2.rb +++ b/ext/tk/sample/demos-jp/entry2.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # entry (with scrollbars) widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/entry3.rb b/ext/tk/sample/demos-jp/entry3.rb index f57dc13553..46426af6ae 100644 --- a/ext/tk/sample/demos-jp/entry3.rb +++ b/ext/tk/sample/demos-jp/entry3.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # entry3.rb -- # # This demonstration script creates several entry widgets whose diff --git a/ext/tk/sample/demos-jp/filebox.rb b/ext/tk/sample/demos-jp/filebox.rb index f3608ab70f..04b4810b3b 100644 --- a/ext/tk/sample/demos-jp/filebox.rb +++ b/ext/tk/sample/demos-jp/filebox.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # widget demo prompts the user to select a file (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/floor.rb b/ext/tk/sample/demos-jp/floor.rb index b029580bd6..b7d07bdafa 100644 --- a/ext/tk/sample/demos-jp/floor.rb +++ b/ext/tk/sample/demos-jp/floor.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # floorDisplay widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/floor2.rb b/ext/tk/sample/demos-jp/floor2.rb index a20b31d45c..b7571a592f 100644 --- a/ext/tk/sample/demos-jp/floor2.rb +++ b/ext/tk/sample/demos-jp/floor2.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # floorDisplay widget demo 2 (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/form.rb b/ext/tk/sample/demos-jp/form.rb index fe456d3943..637dd9a8ea 100644 --- a/ext/tk/sample/demos-jp/form.rb +++ b/ext/tk/sample/demos-jp/form.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # form widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/goldberg.rb b/ext/tk/sample/demos-jp/goldberg.rb index 592b69f775..8bf0104c16 100644 --- a/ext/tk/sample/demos-jp/goldberg.rb +++ b/ext/tk/sample/demos-jp/goldberg.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # Ruby/Tk Goldverg demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/hello b/ext/tk/sample/demos-jp/hello index 859ebd950e..08f154d499 100644 --- a/ext/tk/sample/demos-jp/hello +++ b/ext/tk/sample/demos-jp/hello @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# -*- coding: euc-jp -*- require 'tk' TkButton.new(nil, diff --git a/ext/tk/sample/demos-jp/hscale.rb b/ext/tk/sample/demos-jp/hscale.rb index 37d215435c..b636f0579f 100644 --- a/ext/tk/sample/demos-jp/hscale.rb +++ b/ext/tk/sample/demos-jp/hscale.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- require "tkcanvas" if defined?($hscale_demo) && $hscale_deom @@ -65,7 +66,6 @@ TkFrame.new($hscale_demo) {|frame| scale.set 75 }.pack('side'=>'top', 'fill'=>'x') - def setWidth(w, width) width = width + 21 x2 = width - 30 diff --git a/ext/tk/sample/demos-jp/icon.rb b/ext/tk/sample/demos-jp/icon.rb index e4fef5cae7..26382a57a7 100644 --- a/ext/tk/sample/demos-jp/icon.rb +++ b/ext/tk/sample/demos-jp/icon.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # iconic button widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/image1.rb b/ext/tk/sample/demos-jp/image1.rb index 3d47f844e5..3b56d240dc 100644 --- a/ext/tk/sample/demos-jp/image1.rb +++ b/ext/tk/sample/demos-jp/image1.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # two image widgets demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/image2.rb b/ext/tk/sample/demos-jp/image2.rb index e2e2a2b036..de627448c1 100644 --- a/ext/tk/sample/demos-jp/image2.rb +++ b/ext/tk/sample/demos-jp/image2.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # widget demo 'load image' (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/image3.rb b/ext/tk/sample/demos-jp/image3.rb index d9f378c116..36c1823745 100644 --- a/ext/tk/sample/demos-jp/image3.rb +++ b/ext/tk/sample/demos-jp/image3.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # image3.rb # # This demonstration script creates a simple collection of widgets diff --git a/ext/tk/sample/demos-jp/items.rb b/ext/tk/sample/demos-jp/items.rb index 38774d10d2..c173d3b57f 100644 --- a/ext/tk/sample/demos-jp/items.rb +++ b/ext/tk/sample/demos-jp/items.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # canvas item types widget demo (called by 'widget') # @@ -91,8 +92,13 @@ TkcLine.new(cvs, '0c', '16c', '30c', '16c', 'width'=>2) TkcLine.new(cvs, '10c', '0c', '10c', '24c', 'width'=>2) TkcLine.new(cvs, '20c', '0c', '20c', '24c', 'width'=>2) -font1 = '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' -font2 = '-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*' +if $tk_version =~ /^4.*/ + font1 = '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' + font2 = '-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*' +else + font1 = 'Helvetica 12' + font2 = 'Helvetica 24 bold' +end if TkWinfo.depth($root).to_i > 1 blue = 'DeepSkyBlue3' red = 'red' diff --git a/ext/tk/sample/demos-jp/ixset2 b/ext/tk/sample/demos-jp/ixset2 index 8947daa4b4..5b816e40b1 100644 --- a/ext/tk/sample/demos-jp/ixset2 +++ b/ext/tk/sample/demos-jp/ixset2 @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# -*- coding: euc-jp -*- # # ixset -- # A nice interface to "xset" to change X server settings diff --git a/ext/tk/sample/demos-jp/label.rb b/ext/tk/sample/demos-jp/label.rb index 59626289fc..a1ecc2ec80 100644 --- a/ext/tk/sample/demos-jp/label.rb +++ b/ext/tk/sample/demos-jp/label.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # label widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/labelframe.rb b/ext/tk/sample/demos-jp/labelframe.rb index 23c974dcc2..f16b601ffd 100644 --- a/ext/tk/sample/demos-jp/labelframe.rb +++ b/ext/tk/sample/demos-jp/labelframe.rb @@ -1,3 +1,5 @@ +# -*- coding: euc-jp -*- +# # labelframe.rb # # This demonstration script creates a toplevel window containing diff --git a/ext/tk/sample/demos-jp/menu.rb b/ext/tk/sample/demos-jp/menu.rb index add85f7f7b..6b9e5c9e5e 100644 --- a/ext/tk/sample/demos-jp/menu.rb +++ b/ext/tk/sample/demos-jp/menu.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # menus widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/menu84.rb b/ext/tk/sample/demos-jp/menu84.rb index 8c2a815d78..762cfa53b8 100644 --- a/ext/tk/sample/demos-jp/menu84.rb +++ b/ext/tk/sample/demos-jp/menu84.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # menus widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/menu8x.rb b/ext/tk/sample/demos-jp/menu8x.rb index 050f0decb4..23efa7e790 100644 --- a/ext/tk/sample/demos-jp/menu8x.rb +++ b/ext/tk/sample/demos-jp/menu8x.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # menus widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/menubu.rb b/ext/tk/sample/demos-jp/menubu.rb index aa90a3087f..e73c393aa5 100644 --- a/ext/tk/sample/demos-jp/menubu.rb +++ b/ext/tk/sample/demos-jp/menubu.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- require "tkcanvas" def optionMenu(menubutton, varName, firstValue, *rest) diff --git a/ext/tk/sample/demos-jp/msgbox.rb b/ext/tk/sample/demos-jp/msgbox.rb index 983e6b6589..0fe5db7dd6 100644 --- a/ext/tk/sample/demos-jp/msgbox.rb +++ b/ext/tk/sample/demos-jp/msgbox.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # message boxes widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/paned1.rb b/ext/tk/sample/demos-jp/paned1.rb index 8d16d03c08..137e187417 100644 --- a/ext/tk/sample/demos-jp/paned1.rb +++ b/ext/tk/sample/demos-jp/paned1.rb @@ -1,3 +1,5 @@ +# -*- coding: euc-jp -*- +# # paned1.rb # # This demonstration script creates a toplevel window containing diff --git a/ext/tk/sample/demos-jp/paned2.rb b/ext/tk/sample/demos-jp/paned2.rb index 1e82eddda4..b394432b1c 100644 --- a/ext/tk/sample/demos-jp/paned2.rb +++ b/ext/tk/sample/demos-jp/paned2.rb @@ -1,3 +1,5 @@ +# -*- coding: euc-jp -*- +# # paned2.rb -- # # This demonstration script creates a toplevel window containing diff --git a/ext/tk/sample/demos-jp/pendulum.rb b/ext/tk/sample/demos-jp/pendulum.rb index d703c74d5a..e19b57a2d6 100644 --- a/ext/tk/sample/demos-jp/pendulum.rb +++ b/ext/tk/sample/demos-jp/pendulum.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # This demonstration illustrates how Tcl/Tk can be used to construct # simulations of physical systems. @@ -50,9 +51,11 @@ TkFrame.new($pendulum_demo) {|frame| class PendulumAnimationDemo def initialize(frame) # Create some structural widgets - pane = TkPanedWindow.new(frame).pack(:fill=>:both, :expand=>true) - pane.add(@lf1 = TkLabelFrame.new(pane, :text=>'Pendulum Simulation')) - pane.add(@lf2 = TkLabelFrame.new(pane, :text=>'Phase Space')) + @pane = TkPanedWindow.new(frame).pack(:fill=>:both, :expand=>true) +# @pane.add(@lf1 = TkLabelFrame.new(@pane, :text=>'Pendulum Simulation')) +# @pane.add(@lf2 = TkLabelFrame.new(@pane, :text=>'Phase Space')) + @lf1 = TkLabelFrame.new(@pane, :text=>'Pendulum Simulation') + @lf2 = TkLabelFrame.new(@pane, :text=>'Phase Space') # Create the canvas containing the graphical representation of the # simulated system. @@ -100,23 +103,24 @@ class PendulumAnimationDemo @dTheta = 0.0 @length = 150 - # init display - showPendulum - # animation loop @timer = TkTimer.new(15){ repeat } # binding @c.bindtags_unshift(btag = TkBindTag.new) btag.bind('Destroy'){ @timer.stop } - btag.bind('1', proc{|x, y| @timer.stop; showPendulum(x, y)}, '%x %y') - btag.bind('B1-Motion', proc{|x, y| showPendulum(x, y)}, '%x %y') + btag.bind('1', proc{|x, y| @timer.stop; showPendulum(x.to_i, y.to_i)}, + '%x %y') + btag.bind('B1-Motion', proc{|x, y| showPendulum(x.to_i, y.to_i)}, '%x %y') btag.bind('ButtonRelease-1', - proc{|x, y| showPendulum(x, y); @timer.start }, '%x %y') + proc{|x, y| showPendulum(x.to_i, y.to_i); @timer.start }, + '%x %y') - btag.bind('Configure', proc{|w| @plate.coords(0, 25, w, 25)}, '%w') + btag.bind('Configure', proc{|w| @plate.coords(0, 25, w.to_i, 25)}, '%w') @k.bind('Configure', proc{|h, w| + h = h.to_i + w = w.to_i @psh = h/2; @psw = w/2 @x_axis.coords(2, @psh, w-2, @psh) @@ -125,6 +129,14 @@ class PendulumAnimationDemo @label_dtheta.coords(w-6, @psh+4) }, '%h %w') + # add + Tk.update + @pane.add(@lf1) + @pane.add(@lf2) + + # init display + showPendulum + # animation start @timer.start(500) end @@ -155,6 +167,10 @@ class PendulumAnimationDemo # rate at which the angle is changing (the first derivative with # respect to time.) def showPhase + unless @psw && @psh + @psw = @k.width/2 + @psh = @k.height/2 + end @points << @theta + @psw << -20*@dTheta + @psh if @points.length > 100 @points = @points[-100..-1] diff --git a/ext/tk/sample/demos-jp/plot.rb b/ext/tk/sample/demos-jp/plot.rb index 902b144f72..dbca3e971c 100644 --- a/ext/tk/sample/demos-jp/plot.rb +++ b/ext/tk/sample/demos-jp/plot.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # 2-D plot widget demo (called by 'widget') # @@ -41,7 +42,11 @@ $plot_buttons = TkFrame.new($plot_demo) {|frame| $plot_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') # font ÀßÄê -plotFont = '-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' + if $tk_version =~ /^4.*/ + plotFont = '-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' + else + font = 'Helvetica 18' + end # canvas ÀßÄê $plot_canvas = TkCanvas.new($plot_demo,'relief'=>'raised','width'=>450,'height'=>300) diff --git a/ext/tk/sample/demos-jp/puzzle.rb b/ext/tk/sample/demos-jp/puzzle.rb index ad69775aab..6a3c8c8ef6 100644 --- a/ext/tk/sample/demos-jp/puzzle.rb +++ b/ext/tk/sample/demos-jp/puzzle.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # widet demo 'puzzle' (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/radio.rb b/ext/tk/sample/demos-jp/radio.rb index 5858b4222a..3a11c394a3 100644 --- a/ext/tk/sample/demos-jp/radio.rb +++ b/ext/tk/sample/demos-jp/radio.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # radiobutton widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/radio2.rb b/ext/tk/sample/demos-jp/radio2.rb index 5ac877d99a..b89520cdc5 100644 --- a/ext/tk/sample/demos-jp/radio2.rb +++ b/ext/tk/sample/demos-jp/radio2.rb @@ -1,3 +1,5 @@ +# -*- coding: euc-jp -*- +# # radio2.rb # # This demonstration script creates a toplevel window containing diff --git a/ext/tk/sample/demos-jp/radio3.rb b/ext/tk/sample/demos-jp/radio3.rb index 6e9a0f750b..a223a19bc2 100644 --- a/ext/tk/sample/demos-jp/radio3.rb +++ b/ext/tk/sample/demos-jp/radio3.rb @@ -1,3 +1,5 @@ +# -*- coding: euc-jp -*- +# # radio3.rb # # This demonstration script creates a toplevel window containing diff --git a/ext/tk/sample/demos-jp/rolodex-j b/ext/tk/sample/demos-jp/rolodex-j index dcc18cfa51..6c3ea7a484 100644 --- a/ext/tk/sample/demos-jp/rolodex-j +++ b/ext/tk/sample/demos-jp/rolodex-j @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# -*- coding: euc-jp -*- # # rolodex -- # ¤³¤Î¥¹¥¯¥ê¥×¥È¤Ï Tom LaStrange ¤Î rolodex ¤Î°ìÉô¤Ç¤¹¡£ diff --git a/ext/tk/sample/demos-jp/ruler.rb b/ext/tk/sample/demos-jp/ruler.rb index 94b4c921d3..c913e247d1 100644 --- a/ext/tk/sample/demos-jp/ruler.rb +++ b/ext/tk/sample/demos-jp/ruler.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # ruler widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/sayings.rb b/ext/tk/sample/demos-jp/sayings.rb index ce195a0e53..24b011f5ab 100644 --- a/ext/tk/sample/demos-jp/sayings.rb +++ b/ext/tk/sample/demos-jp/sayings.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # listbox widget demo 'sayings' (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/search.rb b/ext/tk/sample/demos-jp/search.rb index f5268f987f..d3692e2455 100644 --- a/ext/tk/sample/demos-jp/search.rb +++ b/ext/tk/sample/demos-jp/search.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # Text Search widget demo (called by 'widget') # @@ -168,9 +169,14 @@ $search_text.insert('1.0', "\ ¥¨¥ó¥È¥ê¤Ëʸ»úÎó¤òÆþÎϤ·¡¢<¥ê¥¿¡¼¥ó> ¤ò²¡¤¹¤«¡Öȿž¡×¥Ü¥¿¥ó¤ò²¡¤·¤Æ¤¯ \ ¤À¤µ¤¤¡£¤¹¤ë¤È¥Õ¥¡¥¤¥ëÃæ¤Î¡¢¸¡º÷ʸ»úÎó¤È°ìÃפ¹¤ëÉôʬ¤ËÁ´¤Æ \"search_Tag\" \ ¤È¤¤¤¦¥¿¥°¤¬¤Ä¤±¤é¤ì¡¢¥¿¥°¤Îɽ¼¨Â°À­¤È¤·¤Æ¤½¤Îʸ»úÎó¤¬ÅÀÌǤ¹¤ë¤è¤¦¤Ë \ -ÀßÄꤵ¤ì¤Þ¤¹¡£") +ÀßÄꤵ¤ì¤Þ¤¹¡£\n") +$search_text.insert('end', "\ +¥Õ¥¡¥¤¥ëÆɤ߹þ¤ß¤Î¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤Ï \"#{Dir.pwd}\" ¤Ç¤¹¡£\ +") $search_text.set_insert '0.0' $search_fileName.value = '' $search_searchString.value = '' +$search_text.width = 60 +$search_text.height = 20 diff --git a/ext/tk/sample/demos-jp/spin.rb b/ext/tk/sample/demos-jp/spin.rb index c7b8096723..b8eb99c4ed 100644 --- a/ext/tk/sample/demos-jp/spin.rb +++ b/ext/tk/sample/demos-jp/spin.rb @@ -1,3 +1,5 @@ +# -*- coding: euc-jp -*- +# # spin.rb -- # # This demonstration script creates several spinbox widgets. diff --git a/ext/tk/sample/demos-jp/states.rb b/ext/tk/sample/demos-jp/states.rb index dfae821261..3c58711bd1 100644 --- a/ext/tk/sample/demos-jp/states.rb +++ b/ext/tk/sample/demos-jp/states.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # listbox widget demo 'states' (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/style.rb b/ext/tk/sample/demos-jp/style.rb index 59e406bc80..c8c7850156 100644 --- a/ext/tk/sample/demos-jp/style.rb +++ b/ext/tk/sample/demos-jp/style.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # text (display styles) widget demo (called by 'widget') # @@ -8,6 +9,7 @@ if defined?($style_demo) && $style_demo $style_demo = nil end + # demo ÍѤΠtoplevel widget ¤òÀ¸À® $style_demo = TkToplevel.new {|w| title("Text Demonstration - Display Styles") @@ -15,6 +17,7 @@ $style_demo = TkToplevel.new {|w| positionWindow(w) } + # frame À¸À® TkFrame.new($style_demo) {|frame| TkButton.new(frame) { @@ -33,13 +36,15 @@ TkFrame.new($style_demo) {|frame| }.pack('side'=>'left', 'expand'=>'yes') }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') + # text À¸À® -TkText.new($style_demo){|t| +txt = TkText.new($style_demo){|t| # À¸À® setgrid 'true' - width 70 - height 32 + #width 70 + #height 32 wrap 'word' + font $font TkScrollbar.new($style_demo) {|s| pack('side'=>'right', 'fill'=>'y') command proc{|*args| t.yview(*args)} @@ -48,11 +53,20 @@ TkText.new($style_demo){|t| pack('expand'=>'yes', 'fill'=>'both') # ¥Æ¥­¥¹¥È¥¿¥°ÀßÄê (¥Õ¥©¥ó¥È´ØÏ¢) - style_tag_bold = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-O-Normal--*-120-*-*-*-*-*-*') - style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font) + family = 'Courier' + + if $tk_version =~ /^4.*/ + style_tag_bold = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-O-Normal--*-120-*-*-*-*-*-*') + style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font) style_tag_verybig = TkTextTag.new(t, 'font'=>'-*-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*') -# style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font) + # style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font) style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*') + else + style_tag_bold = TkTextTag.new(t, 'font'=>[family, 12, :bold, :italic]) + style_tag_big = TkTextTag.new(t, 'font'=>[family, 14, :bold]) + style_tag_verybig = TkTextTag.new(t, 'font'=>['Helvetica', 24, :bold]) + style_tag_small = TkTextTag.new(t, 'font'=>['Times 8 bold']) + end ### # case($tk_version) # when /^4.*/ @@ -106,8 +120,13 @@ TkText.new($style_demo){|t| style_tag_overstrike = TkTextTag.new(t, 'overstrike'=>'on') style_tag_right = TkTextTag.new(t, 'justify'=>'right') style_tag_center = TkTextTag.new(t, 'justify'=>'center') - style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') - style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') + if $tk_version =~ /^4.*/ + style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') + style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*') + else + style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>[family, 10]) + style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>[family, 10]) + end style_tag_margins = TkTextTag.new(t, 'lmargin1'=>'12m', 'lmargin2'=>'6m', 'rmargin'=>'10m') style_tag_spacing = TkTextTag.new(t, 'spacing1'=>'10p', 'spacing2'=>'2p', @@ -246,3 +265,5 @@ spacing3') } +txt.width 70 +txt.height 32 diff --git a/ext/tk/sample/demos-jp/tcolor b/ext/tk/sample/demos-jp/tcolor index c7f7ec7289..17f7e1347e 100644 --- a/ext/tk/sample/demos-jp/tcolor +++ b/ext/tk/sample/demos-jp/tcolor @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# -*- coding: euc-jp -*- # # tcolor -- # ¤³¤Î¥¹¥¯¥ê¥×¥È¤ÏRGB,HSB,CYM·Á¼°¤ò¥µ¥Ý¡¼¥È¤¹¤ë diff --git a/ext/tk/sample/demos-jp/text.rb b/ext/tk/sample/demos-jp/text.rb index 0057d5dbdc..25e0e64e9a 100644 --- a/ext/tk/sample/demos-jp/text.rb +++ b/ext/tk/sample/demos-jp/text.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # text (basic facilities) widget demo (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/textpeer.rb b/ext/tk/sample/demos-jp/textpeer.rb new file mode 100644 index 0000000000..9b2b57a698 --- /dev/null +++ b/ext/tk/sample/demos-jp/textpeer.rb @@ -0,0 +1,78 @@ +# -*- coding: euc-jp -*- +# +# text widget peering demo (called by 'widget') +# +# based on Tcl/Tk8.5.0 widget demos + +if defined?($textpeer_demo) && $textpeer_demo + $textpeer_demo.destroy + $textpeer_demo = nil +end + +# demo toplevel widget +$textpeer_demo = TkToplevel.new {|w| + title("Text Wdget Peering Demonstration") + iconname("textpeer") + positionWindow(w) +} + +count = [0] + +## Define a widget that we peer from; it won't ever actually be shown though +first = TkText.new($textpeer_demo, :widgetname=>"text#{count[0] += 1}") +first.insert :end,"¤³¤Î¥Ç¥â¤Ï°ì¤Ä¤ÎÁȤòÀ®¤·¤¿¥Æ¥­¥¹¥È¥¦¥£¥¸¥§¥Ã¥È¤ò¼¨¤·¤Þ¤¹¡£" +first.insert :end,"¤½¤ì¤é¤Î¥Æ¥­¥¹¥È¥¦¥£¥¸¥§¥Ã¥È¤ÏÂÐÅù(¥Ô¥¢;peer)¤Î´Ø·¸¤Ë" +first.insert :end,"¤Ê¤Ã¤Æ¤¤¤Þ¤¹¡£" +first.insert :end,"¤½¤ì¤é¤Ï¡¢´ðÈפȤʤë¥Ç¡¼¥¿¥â¥Ç¥ë¤Ï¶¦Ä̤Τâ¤Î¤ò»ý¤Á¤Þ¤¹¤¬¡¢" +first.insert :end,"²èÌÌɽ¼¨°ÌÃÖ¡¢ÊÔ½¸°ÌÃÖ¡¢ÁªÂòÈÏ°Ï(selection)¤Ë¤Ä¤¤¤Æ¤Ï" +first.insert :end,"ÆÈΩ¤Ë»ý¤Ä¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£" +first.insert :end,"³Æ¥Æ¥­¥¹¥È¥¦¥£¥¸¥§¥Ã¥È¤ÎÏƤˤ¢¤ë" +first.insert :end,"¡Ö¥Ô¥¢(peer)¤ÎºîÀ®¡×¥Ü¥¿¥ó¤ò»È¤¨¤Ð¡¢" +first.insert :end,"¿·¤¿¤Ê¥Ô¥¢¤òÄɲ乤뤳¤È¤¬²Äǽ¤Ç¤¹¡£" +first.insert :end,"¤Þ¤¿¡Ö¥Ô¥¢(peer)¤Î¾Ãµî¡×¥Ü¥¿¥ó¤ò»È¤¨¤Ð¡¢" +first.insert :end,"ÆÃÄê¤Î¥Ô¥¢¥¦¥£¥¸¥§¥Ã¥È¤ò¾Ãµî¤¹¤ë¤³¤È¤â¤Ç¤­¤Þ¤¹¡£" + +## Procedures to make and kill clones; most of this is just so that the demo +## looks nice... +def makeClone(count, win, txt) + cnt = (count[0] += 1) + peer = TkText::Peer.new(txt, win, :widgetname=>"text#{cnt}") + sbar = TkScrollbar.new(win, :widgetname=>"sb#{cnt}") + peer.yscrollbar sbar + b1 = TkButton.new(win, :widgetname=>"clone#{cnt}", + :text=>'¥Ô¥¢(peer)¤ÎºîÀ®', + :command=>proc{makeClone(count, win, peer)}) + b2 = TkButton.new(win, :widgetname=>"kill#{cnt}", + :text=>'¥Ô¥¢(peer)¤Î¾Ãµî', + :command=>proc{killClone(win, cnt)}) + row = cnt * 2 + TkGrid.configure(peer, sbar, b1, :sticky=>'nsew', :row=>row) + TkGrid.configure('^', '^', b2, :sticky=>'nsew', :row=>(row+=1)) + TkGrid.configure(b1, b2, :sticky=>'new') + TkGrid.rowconfigure(win, b2, :weight=>1) +end + +def killClone(win, cnt) + Tk.destroy("#{win.path}.text#{cnt}", "#{win.path}.sb#{cnt}", + "#{win.path}.clone#{cnt}", "#{win.path}.kill#{cnt}") +end + +## Now set up the GUI +makeClone(count, $textpeer_demo, first) +makeClone(count, $textpeer_demo, first) +first.destroy + +## See Code / Dismiss buttons +TkFrame.new($textpeer_demo){|f| + TkButton.new(f, :text=>'ÊĤ¸¤ë', :width=>15, :command=>proc{ + $textpeer_demo.destroy + $textpeer_demo = nil + }).pack(:side=>:left, :expand=>true) + + TkButton.new(f, :text=>'¥³¡¼¥É»²¾È', :width=>15, :command=>proc{ + showCode 'textpeer' + }).pack(:side=>:left, :expand=>true) + + TkGrid.configure(f, '-', '-', :sticky=>'ew', :row=>5000) +} +TkGrid.columnconfigure($textpeer_demo, 0, :weight=>1) diff --git a/ext/tk/sample/demos-jp/twind.rb b/ext/tk/sample/demos-jp/twind.rb index 2b228e4acd..d0fa8ca49e 100644 --- a/ext/tk/sample/demos-jp/twind.rb +++ b/ext/tk/sample/demos-jp/twind.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # text (embedded windows) widget demo (called by 'widget') # @@ -206,7 +207,11 @@ def textWindPlot (t) cursor 'top_left_arrow' } - font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' + if $tk_version =~ /^4.*/ + font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*' + else + font = 'Helvetica 18' + end TkcLine.new($twind_plot, 100, 250, 400, 250, 'width'=>2) TkcLine.new($twind_plot, 100, 250, 100, 50, 'width'=>2) diff --git a/ext/tk/sample/demos-jp/twind2.rb b/ext/tk/sample/demos-jp/twind2.rb index b634f07b4b..e8009cef19 100644 --- a/ext/tk/sample/demos-jp/twind2.rb +++ b/ext/tk/sample/demos-jp/twind2.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- # # text (embedded windows) widget demo 2 (called by 'widget') # diff --git a/ext/tk/sample/demos-jp/unicodeout.rb b/ext/tk/sample/demos-jp/unicodeout.rb index 090cdf3059..7ab415fe57 100644 --- a/ext/tk/sample/demos-jp/unicodeout.rb +++ b/ext/tk/sample/demos-jp/unicodeout.rb @@ -1,3 +1,5 @@ +# -*- coding: euc-jp -*- +# # unicodeout.rb -- # # This demonstration script shows how you can produce output (in label diff --git a/ext/tk/sample/demos-jp/vscale.rb b/ext/tk/sample/demos-jp/vscale.rb index 86f6f7cdee..990ca43215 100644 --- a/ext/tk/sample/demos-jp/vscale.rb +++ b/ext/tk/sample/demos-jp/vscale.rb @@ -1,3 +1,4 @@ +# -*- coding: euc-jp -*- require "tkcanvas" if defined?($vscale_demo) && $vscale_demo @@ -66,7 +67,6 @@ TkFrame.new($vscale_demo) {|frame| scale.set 75 }.pack - def setHeight(w, height) height = height + 21 y2 = height - 30 @@ -76,3 +76,4 @@ def setHeight(w, height) w.coords 'poly',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20 w.coords 'line',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20 end + diff --git a/ext/tk/sample/demos-jp/widget b/ext/tk/sample/demos-jp/widget index c84436481a..3eea4c7887 100644 --- a/ext/tk/sample/demos-jp/widget +++ b/ext/tk/sample/demos-jp/widget @@ -1,14 +1,20 @@ #!/usr/bin/env ruby +# -*- coding: euc-jp -*- # ´Á»ú¥³¡¼¥ÉÀßÄê ( tk.rb ¤Î¥í¡¼¥É»þ¤Î encoding ¿äÄê/ÀßÄê¤Ë»È¤ï¤ì¤ë ) -$KCODE = 'euc' +if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!!!! + $KCODE = 'euc' +else + DEFAULT_TK_ENCODING = 'EUC-JP' +end # tk ´Ø·¸¥é¥¤¥Ö¥é¥ê¤ÎÆɤ߹þ¤ß require 'tk' # require 'tkafter' # widget demo directory °ÌÃ֤γÍÆÀ -$demo_dir = File.dirname($0) +# $demo_dir = File.dirname($0) +$demo_dir = File.dirname(__FILE__) # root ¤ÎÀ¸À® $root = TkRoot.new{title "Ruby/Tk Widget Demonstration"} @@ -40,18 +46,17 @@ when /^4.*/ # $msg_kanji_font=TkFont.new('Helvetica 16', 'Gothic 16 bold') when /^8.*/ - $font = TkFont.new('Helvetica -12') - $kanji_font = TkFont.new('Helvetica -12', 'Mincho -12') + $font = TkFont.new('Helvetica 12') + $kanji_font = TkFont.new('Helvetica 12', 'Mincho 12') TkOption.add('*kanjiFont', knjfont, 'startupFile') - $msg_kanji_font=TkFont.new('Helvetica 16', 'Gothic 16 bold') + $msg_kanji_font=TkFont.new('Helvetica 18 bold', 'Gothic 18 bold') else - $font = TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*', nil) + $font = TkFont.new('Helvetica 14', nil) knjfont = '-*--16-*-jisx0208.1983-0' - $kanji_font = TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*', - knjfont) + $kanji_font = TkFont.new('Helvetic 14', knj) TkOption.add('*kanjiFont', knjfont, 'startupFile') - $msg_kanji_font=TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*', + $msg_kanji_font=TkFont.new('Helvetica 14', '-*--24-*-jisx0208.1983-0') end ####### @@ -180,18 +185,27 @@ else textFrame.pack('expand'=>'yes', 'fill'=>'both') statusBar = TkFrame.new($root) {|f| + if $tk_version =~ /^4.*/ + statusfont = '-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*' + else + statusfont = 'Helvetica 10' + end $statusBarLabel = \ TkLabel.new(f, 'text'=>" ", 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') \ + 'font'=>statusfont) \ .pack('side'=>'left', 'padx'=>2, 'expand'=>'yes', 'fill'=>'both') TkLabel.new(f, 'width'=>8, 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w', - 'font'=>'-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') \ + 'font'=>statusfont) \ .pack('side'=>'left', 'padx'=>2) }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>2) end # ¥Æ¥­¥¹¥È¥¿¥°ÀßÄê -tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*') +if $tk_version =~ /^4.*/ + tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*') +else + tag_title = TkTextTag.new(txt, 'font'=>'Helvetica 18 bold') +end #tag_kanji_title = TkTextTag.new(txt, 'kanjifont'=>$msg_kanji_font) #tag_middle = TkTextTag.new(txt, 'kanjifont'=>$kanji_font) tag_kanji_title = TkTextTag.new(txt, 'font'=>$msg_kanji_font) @@ -367,6 +381,8 @@ txt.insert('end', "5. txt.insert('end', " \n ", tag_demospace) txt.insert('end', "6. ¸¡º÷\n", tag_demo, "demo-search") txt.insert('end', " \n ", tag_demospace) +txt.insert('end', "7. ¥Æ¥­¥¹¥È¥¦¥£¥¸¥§¥Ã¥È¤ÎÂÐÅù²½(peering) (µ¡Ç½¤ËÂбþ¤·¤¿¥Ð¡¼¥¸¥ç¥ó¤ÎTk¤¬É¬Í×)\n", tag_demo, "demo-textpeer") +txt.insert('end', " \n ", tag_demospace) txt.insert('end', "\n") #txt.insert('end', "¥­¥ã¥ó¥Ð¥¹\n", tag_middle) @@ -487,7 +503,11 @@ def showVars1(parent, *args) text "ÊÑ¿ôÃÍ:" width 20 anchor 'center' - font '-Adobe-helvetica-medium-r-normal--*-180-*-*-*-*-*-*' + if $tk_version =~ /^4.*/ + font '-Adobe-helvetica-medium-r-normal--*-180-*-*-*-*-*-*' + else + font 'Helvetica 14' + end }.pack('side'=>'top', 'fill'=>'x') len = 1 args.each{|vnam,vbody| @@ -635,8 +655,8 @@ private :_null_binding def eval_samplecode(code) #eval(code) - _null_binding.pseudo_toplevel_eval{ eval(code) } - #Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } } + #_null_binding.pseudo_toplevel_eval{ eval(code) } + Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } } Tk.update end @@ -928,7 +948,7 @@ end # def aboutBox Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo', - 'message'=>"Ruby/Tk ¥¦¥£¥¸¥§¥Ã¥È¥Ç¥â Ver.1.6.2-jp\n\n" + + 'message'=>"Ruby/Tk ¥¦¥£¥¸¥§¥Ã¥È¥Ç¥â Ver.1.6.3-jp\n\n" + "based on demos of Tk8.1 -- 8.5 " + "( Copyright:: " + "(c) 1996-1997 Sun Microsystems, Inc. / " + diff --git a/ext/tk/sample/encstr_usage.rb b/ext/tk/sample/encstr_usage.rb index 4285ec861c..b22c2504ac 100644 --- a/ext/tk/sample/encstr_usage.rb +++ b/ext/tk/sample/encstr_usage.rb @@ -11,7 +11,7 @@ t1 = TkText.new(:height=>5).pack t2 = TkText.new(:height=>5).pack t3 = TkText.new(:height=>5).pack -src_str = IO.readlines('iso2022-kr.txt').join +src_str = IO.readlines(File.join(File.dirname(__FILE__),'iso2022-kr.txt')).join t1.insert('end', "use neither Tk::EncodedString class nor Tk.encoding= method\n\n") @@ -23,7 +23,8 @@ t2.insert('end', t2.insert('end', enc_str) Tk.encoding = 'iso2022-kr' -t3.insert('end', "use Tk.encoding = 'iso2022-kr'\n\n") +t3.insert('end', "use Tk.encoding = 'iso2022-kr' (Tk.force_default_encoding? == #{Tk.force_default_encoding?})\n\n") + t3.insert('end', src_str) Tk.mainloop diff --git a/ext/tk/sample/irbtkw.rbw b/ext/tk/sample/irbtkw.rbw index f6a35be6ed..3fb6dde626 100644 --- a/ext/tk/sample/irbtkw.rbw +++ b/ext/tk/sample/irbtkw.rbw @@ -4,7 +4,7 @@ # # by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) # -release = '2006/11/06' +release = '2008/03/08' require 'tk' begin @@ -15,10 +15,32 @@ end require 'irb' +if TkCore::WITH_ENCODING +else + # $KCODE setup + case Tk.encoding + when 'shiftjis', 'cp932' + $KCODE='SJIS' + when 'euc-jp' + $KCODE='EUC' + when 'utf-8', 'unicode' + $KCODE='UTF8' + else + # unknown + end +end + # console setup top = TkToplevel.new(:title=>'IRB console') top.protocol(:WM_DELETE_WINDOW){ Tk.exit } +case (Tk.windowingsystem) +when 'win32' + fnt = ['MS Gothic', '-12'] +else + fnt = ['courier', '-12'] +end + console = TkTextIO.new(top, :mode=>:console, :width=>80).pack(:side=>:left, :expand=>true, :fill=>:both) diff --git a/ext/tk/sample/tcltklib/sample2.rb b/ext/tk/sample/tcltklib/sample2.rb index 444bb1eef7..110e81ebc4 100644 --- a/ext/tk/sample/tcltklib/sample2.rb +++ b/ext/tk/sample/tcltklib/sample2.rb @@ -41,7 +41,7 @@ class Othello [ 1, -1], [ 1, 0], [ 1, 1] ] - attr :com_disk, TRUE + attr_accessor :com_disk def initialize(othello) @othello = othello diff --git a/ext/tk/sample/tkextlib/tile/demo.rb b/ext/tk/sample/tkextlib/tile/demo.rb index b604410da4..1a9c029701 100644 --- a/ext/tk/sample/tkextlib/tile/demo.rb +++ b/ext/tk/sample/tkextlib/tile/demo.rb @@ -20,6 +20,12 @@ def version?(ver) TkPackage.vcompare(Tk::Tile.package_version, ver) >= 0 end +# define Tcl/Tk procedures for compatibility +Tk::Tile.__define_LoadImages_proc_for_compatibility__! +Tk::Tile::Style.__define_wrapper_proc_for_compatibility__! + +Tk::Tile::Style.theme_create('step') + Tk.load_tclscript(File.join(demodir, 'toolbutton.tcl')) Tk.load_tclscript(File.join(demodir, 'repeater.tcl')) @@ -55,7 +61,7 @@ $V = TkVariable.new_hash(:THEME => 'default', :CHOICE => 2) # Add in any available loadable themes. -TkPackage.names.find_all{|n| n =~ /^tile::theme::/}.each{|pkg| +TkPackage.names.find_all{|n| n =~ /^(tile|ttk)::theme::/}.each{|pkg| name = pkg.split('::')[-1] unless $THEMELIST.assoc(name) $THEMELIST << [name, Tk.tk_call('string', 'totitle', name)] @@ -66,7 +72,8 @@ TkPackage.names.find_all{|n| n =~ /^tile::theme::/}.each{|pkg| $RUBY_THEMELIST = [] begin load(File.join(demodir, 'themes', 'kroc.rb'), true) -rescue +rescue => e +raise e $RUBY_THEMELIST << ['kroc-rb', 'Kroc (by Ruby)', false] else $RUBY_THEMELIST << ['kroc-rb', 'Kroc (by Ruby)', true] @@ -79,8 +86,8 @@ def makeThemeControl(parent) :variable=>$V.ref(:THEME), :command=>proc{setTheme(theme)}) b.grid(:sticky=>:ew) - unless (TkPackage.names.find{|n| n == "tile::theme::#{theme}"}) - b.state(:disabled) + unless (TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/}) + b.ttk_state(:disabled) end } $RUBY_THEMELIST.each{|theme, name, available| @@ -88,7 +95,7 @@ def makeThemeControl(parent) :variable=>$V.ref(:THEME), :command=>proc{setTheme(theme)}) b.grid(:sticky=>:ew) - b.state(:disabled) unless available + b.ttk_state(:disabled) unless available } c end @@ -98,7 +105,7 @@ def makeThemeMenu(parent) $THEMELIST.each{|theme, name| m.add(:radiobutton, :label=>name, :variable=>$V.ref(:THEME), :value=>theme, :command=>proc{setTheme(theme)}) - unless (TkPackage.names.find{|n| n == "tile::theme::#{theme}"}) + unless (TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/}) m.entryconfigure(:end, :state=>:disabled) end } @@ -111,8 +118,10 @@ def makeThemeMenu(parent) end def setTheme(theme) - if (TkPackage.names.find{|n| n == "tile::theme::#{theme}"}) - TkPackage.require("tile::theme::#{theme}") + if (pkg = TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/}) + unless Tk::Tile::Style.theme_names.find{|n| n == theme} + TkPackage.require(pkg) + end end Tk::Tile::Style.theme_use(theme) end @@ -675,7 +684,7 @@ values = %w(list abc def ghi jkl mno pqr stu vwx yz) combo, :values=>values, :textvariable=>$V.ref(:COMBO)) cb.pack(:side=>:top, :padx=>2, :pady=>2, :expand=>false, :fill=>:x) if i == 1 - cb.state :readonly + cb.ttk_state :readonly begin cb.current = 3 # ignore if unsupported (tile0.4) rescue @@ -922,11 +931,11 @@ end def updateStates $states_list.each{|st| begin - $State[st] = $Widget.window.instate(st) + $State[st] = $Widget.window.ttk_instate(st) rescue - $states_btns[st].state('disabled') + $states_btns[st].ttk_state('disabled') else - $states_btns[st].state('!disabled') + $states_btns[st].ttk_state('!disabled') end } end @@ -934,9 +943,9 @@ end def changeState(st) if $Widget.value != '' if $State.bool_element(st) - $Widget.window.state(st) + $Widget.window.ttk_state(st) else - $Widget.window.state("!#{st}") + $Widget.window.ttk_state("!#{st}") end end end diff --git a/ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tcl b/ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tcl index 19ddda7c73..4facac70d8 100644 --- a/ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tcl +++ b/ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tcl @@ -1,6 +1,6 @@ # Package index for tile demo pixmap themes. if {[file isdirectory [file join $dir blue]]} { - package ifneeded tile::theme::blue 0.0.1 \ + package ifneeded tile::theme::blue 0.7 \ [list source [file join $dir blue.tcl]] } diff --git a/ext/tk/sample/tkextlib/tile/themes/kroc.rb b/ext/tk/sample/tkextlib/tile/themes/kroc.rb index f67ce7a897..27006d847f 100644 --- a/ext/tk/sample/tkextlib/tile/themes/kroc.rb +++ b/ext/tk/sample/tkextlib/tile/themes/kroc.rb @@ -95,8 +95,35 @@ def kroc_rb_settings # # Elements: # - if TkPackage.vcompare(Tk::Tile.package_version, '0.5') >= 0 + if Tk::Tile::TILE_SPEC_VERSION_ID >= 8 + Tk::Tile::Style.element_create('Button.button', + :image, + [ $images['button-n'], + :pressed, $images['button-p'], + :active, $images['button-h'], + ], :border=>3, :sticky=>:ew) + + Tk::Tile::Style.element_create('Checkbutton.indicator', + :image, + [ $images['check-nu'], + [:pressed, :selected],$images['check-nc'], + :pressed, $images['check-nu'], + [:active, :selected], $images['check-hc'], + :active, $images['check-hu'], + :selected, $images['check-nc'], + ], :sticky=>:w) + Tk::Tile::Style.element_create('Radiobutton.indicator', + :image, + [ $images['radio-nu'], + [:pressed,:selected],$images['radio-nc'], + :pressed, $images['radio-nu'], + [:active,:selected], $images['radio-hc'], + :active, $images['radio-hu'], + :selected, $images['radio-nc'], + ], :sticky=>:w) + + elsif TkPackage.vcompare(Tk::Tile.package_version, '0.5') >= 0 Tk::Tile::Style.element_create('Button.button', :image, $images['button-n'], :map=>[ @@ -125,7 +152,6 @@ def kroc_rb_settings ], :sticky=>:w) else # tile 0.4 or earlier - Tk::Tile::Style.element_create('Button.button', :pixmap, :images=>[ :pressed, $images['button-p'], diff --git a/ext/tk/sample/tkextlib/vu/canvSticker2.rb b/ext/tk/sample/tkextlib/vu/canvSticker2.rb index f54e748660..548a72c2cb 100644 --- a/ext/tk/sample/tkextlib/vu/canvSticker2.rb +++ b/ext/tk/sample/tkextlib/vu/canvSticker2.rb @@ -20,14 +20,16 @@ c.destroy #--- #--- set STRING {{x0 y0 x1 y1} {...text...} {resize point: center} -#sti_conf = [ [10, 10, 180, 180], "Sticker äöüß@²³¼½¾", :center ] -#txt_conf = [ [210, 210], "Text äöüß@²³¼½¾", :center ] +#sti_conf = [ [10, 10, 180, 180], "Sticker äöüß@²³¼½¾", :center ] +#txt_conf = [ [210, 210], "Text äöüß@²³¼½¾", :center ] sti_conf = [ [10, 10, 350, 350], - Tk::UTF8_String("Sticker äöüß@²³¼½¾"), :center ] + Tk::UTF8_String('Sticker \u00E4\u00F6\u00FC\u00DF\u0040\u00B2\u00B3\u00BC\u00BD\u00BE'), + :center ] txt_conf = [ [250, 250], - Tk::UTF8_String("Text äöüß@²³¼½¾"), :center ] + Tk::UTF8_String('Text \u00E4\u00F6\u00FC\u00DF\u0040\u00B2\u00B3\u00BC\u00BD\u00BE'), + :center ] -p sti_conf +#p sti_conf fnt = TkFont.new('Helvetica 24 bold') diff --git a/ext/tk/sample/tkrttimer.rb b/ext/tk/sample/tkrttimer.rb index 531f4a8d5a..0abd4ecbd2 100644 --- a/ext/tk/sample/tkrttimer.rb +++ b/ext/tk/sample/tkrttimer.rb @@ -17,8 +17,17 @@ TkLabel.new(f2, :text=>'use TkRTTimer class').pack label2 = TkLabel.new(:parent=>f2, :relief=>:raised, :width=>10).pack(:fill=>:both) -TkLabel.new(:text=>'Interval setting of each timer is 10 ms.', - :padx=>10, :pady=>5).pack +TkLabel.new(:padx=>10, :pady=>5, :justify=>'left', :text=><v).pack(:pady=>[1, 10]) + +a = TkButton.new(:text=>"button A :: proc{p ['AAA', v.value]}").pack(:fill=>:x, :pady=>[1, 15], :padx=>15) +a.command{p ['AAA', v.value]} + +TkLabel.new(:text=>'Callback of the button B returns LIFO order').pack +b = TkButton.new(:text=>"button B :: proc{n = v.value; p ['B:start', n]; Tk.sleep(10000); p ['B:end', n]}").pack(:fill=>:x, :pady=>[1, 15], :padx=>15) +b.command{n = v.value; p ['B:start', n]; Tk.sleep(10000); p ['B:end', n]} + +TkLabel.new(:text=>'Callback of the button C returns FIFO order').pack +c = TkButton.new(:text=>"button C :: proc{n = v.value; Thread.new{p ['C:start', n]; Tk.sleep(10000); p ['C:end', n]}}").pack(:fill=>:x, :pady=>[1, 15], :padx=>15) +c.command{n = v.value; Thread.new{p ['C:start', n]; Tk.sleep(10000); p ['C:end', n]}} + +TkLabel.new(:text=>'Callback of the button D blocks eventloop (no respond to event)').pack +d = TkButton.new(:text=>"button D :: proc{n = v.value; p ['D:start', n]; sleep(10); p ['D:end', n]}").pack(:fill=>:x, :pady=>[1,15], :padx=>15) +d.command{n = v.value; p ['D:start', n]; sleep(10); p ['D:end', n]} + +TkLabel.new(:text=>'Callback of the button E is another way to avoid eventloop blocking').pack +e = TkButton.new(:text=>"button E :: proc{n = v.value; Thread.new{p ['D:start', n]; sleep(10); p ['D:end', n]}}").pack(:fill=>:x, :pady=>[1,15], :padx=>15) +e.command{n = v.value; Thread.new{p ['D:start', n]; sleep(10); p ['D:end', n]}} + +TkButton.new(:text=>'QUIT', :command=>proc{exit}).pack + +TkTimer.new(500, -1){v.numeric += 1}.start + +Tk.mainloop diff --git a/ext/tk/sample/ttk_wrapper.rb b/ext/tk/sample/ttk_wrapper.rb new file mode 100644 index 0000000000..30ae0ece53 --- /dev/null +++ b/ext/tk/sample/ttk_wrapper.rb @@ -0,0 +1,154 @@ +#!/usr/bin/env ruby +# +# ttk_wrapper.rb -- use Ttk widgets as default on old Ruby/Tk scripts +# +# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) +# +version = '0.1' +# +########################################################################## +# parse commandline arguments +########################################################################## +require 'optparse' +opt = OptionParser.new("Usage: #{$0} [options] rubytk_script" << "\n " << + "Ruby/Tk script wrapper. Use Ttk widgets as default.") +opt.version = version + +OPTS = {} +OPTS[:themedir] = [] +OPTS[:rb_theme] = [] +OPTS[:theme] = 'default' + +opt.on('-l', '--list', 'list available theme names'){|v| OPTS[:list] = true} +opt.on('-t', '--theme theme', 'theme name'){|v| OPTS[:theme] = v} +opt.on('-d', '--themedir themes_dir', 'directory of theme definitions'){|v| + OPTS[:themedir] << v +} +opt.on('-r', '--rubytheme rb_theme', 'theme definition file (ruby script)'){|v| + OPTS[:rb_theme] << v +} +opt.on('-v', '--verbose', 'print verbose messages'){|v| OPTS[:verbose] = true} + +opt.parse!(ARGV) + + +########################################################################## +# load Ttk (Tile) extension +########################################################################## +require 'tk' + +begin + require 'tkextlib/tile' + Tk.default_widget_set = :Ttk +rescue LoadError + if OPTS[:verbose] + print "warning: fail to load 'Ttk' extension. use standard widgets.\n" + end +end + +if OPTS[:verbose] + print "current default widget set is '#{Tk.default_widget_set}'\n" +end + + +########################################################################## +# use themes defined on the demo of Ttk (Tile) extension +########################################################################## +demodir = File.dirname(__FILE__) +demo_themesdir = File.expand_path(File.join(demodir, 'tkextlib', 'tile', 'themes')) + +Tk::AUTO_PATH.lappend(*OPTS[:themedir]) unless OPTS[:themedir].empty? +Tk::AUTO_PATH.lappend('.', demodir, demo_themesdir) + +OPTS[:themedir] << demo_themesdir +print "theme-dirs: #{OPTS[:themedir].inspect}\n" if OPTS[:verbose] + +OPTS[:themedir].each{|themesdir| + if File.directory?(themesdir) + Dir.foreach(themesdir){|name| + next if name == '.' || name == '..' + path = File.join(themesdir, name) + Tk::AUTO_PATH.lappend(path) if File.directory?(path) + } + end +} + +# This forces an update of the available packages list. It's required +# for package names to find the themes in demos/themes/*.tcl +Tk.ip_eval("#{TkPackage.unknown_proc} Tcl #{TkPackage.provide('Tcl')}") + +# load themes written in Ruby. +themes_by_ruby = [File.join(demo_themesdir, 'kroc.rb')] +themes_by_ruby.concat OPTS[:rb_theme] +print "ruby-themes: #{themes_by_ruby.inspect}\n" if OPTS[:verbose] + +themes_by_ruby.each{|f| + begin + load(f, true) + rescue LoadError + print "fail to load \"#{f}\"\n" if OPTS[:verbose] + end +} + + +########################################################################## +# define Tcl/Tk procedures for compatibility. +# those are required when want to use themes included +# in "sample/tkextlib/tile/demo.rb". +########################################################################## +Tk::Tile.__define_LoadImages_proc_for_compatibility__! +Tk::Tile::Style.__define_wrapper_proc_for_compatibility__! + + +########################################################################## +# ignore unsupported options of Ttk widgets +########################################################################## +TkConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__! true +TkItemConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__! true + + +########################################################################## +# define utility method +########################################################################## +def setTheme(theme) + unless Tk::Tile::Style.theme_names.find{|n| n == theme} + if (pkg = TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/}) + TkPackage.require(pkg) + end + end + Tk::Tile::Style.theme_use(theme) +end + + +########################################################################## +# make theme name list +########################################################################## +ThemesList = Tk::Tile::Style.theme_names +TkPackage.names.find_all{|n| n =~ /^(tile|ttk)::theme::/}.each{|pkg| + ThemesList << pkg.split('::')[-1] +} +ThemesList.uniq! + + +########################################################################## +# set theme of widget style +########################################################################## +if OPTS[:list] || OPTS[:verbose] + print "supported theme names: #{ThemesList}\n" + exit if OPTS[:list] && ARGV.empty? +end +print "use theme: \"#{OPTS[:theme]}\"\n" if OPTS[:theme] && OPTS[:verbose] +setTheme(OPTS[:theme]) if OPTS[:theme] + + +########################################################################## +# load script +########################################################################## +if (script = File.expand_path(ARGV.shift)) + print "load script \"#{script}\"\n" if OPTS[:verbose] + load(script) +else + print "Error: no script is given.\n" + print opt.help + exit(1) +end diff --git a/ext/tk/stubs.c b/ext/tk/stubs.c index 23ff42a4f4..6d3b330f0e 100644 --- a/ext/tk/stubs.c +++ b/ext/tk/stubs.c @@ -1,5 +1,11 @@ -#include "stubs.h" +/************************************************ + + stubs.c - Tcl/Tk stubs support + +************************************************/ + #include "ruby.h" +#include "stubs.h" #include #include @@ -86,8 +92,12 @@ static DL_HANDLE tcl_dll = (DL_HANDLE)0; static DL_HANDLE tk_dll = (DL_HANDLE)0; int +#ifdef RUBY_VM +ruby_open_tcl_dll(char *appname) +#else ruby_open_tcl_dll(appname) char *appname; +#endif { void (*p_Tcl_FindExecutable)(const char *); int n; @@ -141,8 +151,8 @@ ruby_open_tk_dll() char tk_name[20]; if (!tcl_dll) { - /* int ret = ruby_open_tcl_dll(RSTRING(rb_argv0)->ptr); */ - int ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0); + /* int ret = ruby_open_tcl_dll(RSTRING_PTR(rb_argv0)); */ + int ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0); if (ret != TCLTK_STUBS_OK) return ret; } @@ -169,8 +179,12 @@ ruby_open_tk_dll() } int +#ifdef RUBY_VM +ruby_open_tcltk_dll(char *appname) +#else ruby_open_tcltk_dll(appname) char *appname; +#endif { return( ruby_open_tcl_dll(appname) || ruby_open_tk_dll() ); } @@ -189,8 +203,12 @@ tk_stubs_init_p() Tcl_Interp * +#ifdef RUBY_VM +ruby_tcl_create_ip_and_stubs_init(int *st) +#else ruby_tcl_create_ip_and_stubs_init(st) int *st; +#endif { Tcl_Interp *tcl_ip; @@ -213,8 +231,8 @@ ruby_tcl_create_ip_and_stubs_init(st) Tcl_Interp *(*p_Tcl_DeleteInterp)(); if (!tcl_dll) { - /* int ret = ruby_open_tcl_dll(RSTRING(rb_argv0)->ptr); */ - int ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0); + /* int ret = ruby_open_tcl_dll(RSTRING_PTR(rb_argv0)); */ + int ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0); if (ret != TCLTK_STUBS_OK) { if (st) *st = ret; @@ -272,8 +290,12 @@ ruby_tcl_stubs_init() } int +#ifdef RUBY_VM +ruby_tk_stubs_init(Tcl_Interp *tcl_ip) +#else ruby_tk_stubs_init(tcl_ip) Tcl_Interp *tcl_ip; +#endif { Tcl_ResetResult(tcl_ip); @@ -308,8 +330,12 @@ ruby_tk_stubs_init(tcl_ip) } int +#ifdef RUBY_VM +ruby_tk_stubs_safeinit(Tcl_Interp *tcl_ip) +#else ruby_tk_stubs_safeinit(tcl_ip) Tcl_Interp *tcl_ip; +#endif { Tcl_ResetResult(tcl_ip); @@ -348,8 +374,8 @@ ruby_tcltk_stubs() int st; Tcl_Interp *tcl_ip; - /* st = ruby_open_tcltk_dll(RSTRING(rb_argv0)->ptr); */ - st = ruby_open_tcltk_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0); + /* st = ruby_open_tcltk_dll(RSTRING_PTR(rb_argv0)); */ + st = ruby_open_tcltk_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0); switch(st) { case NO_FindExecutable: return -7; @@ -395,8 +421,12 @@ static int open_tcl_dll = 0; static int call_tk_stubs_init = 0; int +#ifdef RUBY_VM +ruby_open_tcl_dll(char *appname) +#else ruby_open_tcl_dll(appname) char *appname; +#endif { if (appname) { Tcl_FindExecutable(appname); @@ -408,18 +438,24 @@ ruby_open_tcl_dll(appname) return TCLTK_STUBS_OK; } -int ruby_open_tk_dll() +int +ruby_open_tk_dll() { if (!open_tcl_dll) { - /* ruby_open_tcl_dll(RSTRING(rb_argv0)->ptr); */ - ruby_open_tcl_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0); + /* ruby_open_tcl_dll(RSTRING_PTR(rb_argv0)); */ + ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0); } return TCLTK_STUBS_OK; } -int ruby_open_tcltk_dll(appname) +int +#ifdef RUBY_VM +ruby_open_tcltk_dll(char *appname) +#else +ruby_open_tcltk_dll(appname) char *appname; +#endif { return( ruby_open_tcl_dll(appname) || ruby_open_tk_dll() ); } @@ -437,14 +473,18 @@ tk_stubs_init_p() } Tcl_Interp * +#ifdef RUBY_VM +ruby_tcl_create_ip_and_stubs_init(int *st) +#else ruby_tcl_create_ip_and_stubs_init(st) int *st; +#endif { Tcl_Interp *tcl_ip; if (!open_tcl_dll) { - /* ruby_open_tcl_dll(RSTRING(rb_argv0)->ptr); */ - ruby_open_tcl_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0); + /* ruby_open_tcl_dll(RSTRING_PTR(rb_argv0)); */ + ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0); } if (st) *st = 0; @@ -466,8 +506,12 @@ ruby_tcl_stubs_init() } int +#ifdef RUBY_VM +ruby_tk_stubs_init(Tcl_Interp *tcl_ip) +#else ruby_tk_stubs_init(tcl_ip) Tcl_Interp *tcl_ip; +#endif { if (Tk_Init(tcl_ip) == TCL_ERROR) return FAIL_Tk_Init; @@ -483,8 +527,12 @@ ruby_tk_stubs_init(tcl_ip) } int +#ifdef RUBY_VM +ruby_tk_stubs_safeinit(Tcl_Interp *tcl_ip) +#else ruby_tk_stubs_safeinit(tcl_ip) Tcl_Interp *tcl_ip; +#endif { #if TCL_MAJOR_VERSION >= 8 if (Tk_SafeInit(tcl_ip) == TCL_ERROR) @@ -508,8 +556,8 @@ ruby_tk_stubs_safeinit(tcl_ip) int ruby_tcltk_stubs() { - /* Tcl_FindExecutable(RSTRING(rb_argv0)->ptr); */ - Tcl_FindExecutable(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0); + /* Tcl_FindExecutable(RSTRING_PTR(rb_argv0)); */ + Tcl_FindExecutable(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0); return 0; } diff --git a/ext/tk/tcltklib.c b/ext/tk/tcltklib.c index ff1f7640bd..18e0fd76fb 100644 --- a/ext/tk/tcltklib.c +++ b/ext/tk/tcltklib.c @@ -4,11 +4,20 @@ * Oct. 24, 1997 Y. Matsumoto */ -#define TCLTKLIB_RELEASE_DATE "2006-12-01" +#define TCLTKLIB_RELEASE_DATE "2008-03-29" #include "ruby.h" + +#ifdef RUBY_VM +/* #include "ruby/ruby.h" */ +#include "ruby/signal.h" +#include "ruby/encoding.h" +#else +/* #include "ruby.h" */ #include "rubysig.h" #include "version.h" +#endif + #undef EXTERN /* avoid conflict with tcl.h of tcl8.2 or before */ #include #ifdef HAVE_STDARG_PROTOTYPES @@ -30,6 +39,24 @@ #define TCL_FINAL_RELEASE 2 #endif +static struct { + int major; + int minor; + int patchlevel; + int type; +} tcltk_version = {0, 0, 0, 0}; + +static void +set_tcltk_version() +{ + if (tcltk_version.major) return; + + Tcl_GetVersion(&(tcltk_version.major), + &(tcltk_version.minor), + &(tcltk_version.patchlevel), + &(tcltk_version.type)); +} + #if TCL_MAJOR_VERSION >= 8 # ifndef CONST84 # if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 4 /* Tcl8.0.x -- 8.4b1 */ @@ -83,6 +110,26 @@ static void ip_finalize _((Tcl_Interp*)); static int at_exit = 0; +#ifdef RUBY_VM +static VALUE cRubyEncoding; + +/* encoding */ +static int ENCODING_INDEX_UTF8; +static int ENCODING_INDEX_BINARY; +#endif +static VALUE ENCODING_NAME_UTF8; +static VALUE ENCODING_NAME_BINARY; + +static VALUE create_dummy_encoding_for_tk_core _((VALUE, VALUE, VALUE)); +static VALUE create_dummy_encoding_for_tk _((VALUE, VALUE)); +static int update_encoding_table _((VALUE, VALUE, VALUE)); +static VALUE encoding_table_get_name_core _((VALUE, VALUE, VALUE)); +static VALUE encoding_table_get_obj_core _((VALUE, VALUE, VALUE)); +static VALUE encoding_table_get_name _((VALUE, VALUE)); +static VALUE encoding_table_get_obj _((VALUE, VALUE)); +static VALUE create_encoding_table _((VALUE)); +static VALUE ip_get_encoding_table _((VALUE)); + /* for callback break & continue */ static VALUE eTkCallbackReturn; @@ -101,6 +148,9 @@ static VALUE tcltkip_class; static ID ID_at_enc; static ID ID_at_interp; +static ID ID_encoding_name; +static ID ID_encoding_table; + static ID ID_stop_p; static ID ID_alive_p; static ID ID_kill; @@ -124,11 +174,30 @@ static VALUE ip_invoke _((int, VALUE*, VALUE)); static VALUE tk_funcall _((VALUE(), int, VALUE*, VALUE)); +/* Tcl's object type */ +#if TCL_MAJOR_VERSION >= 8 +static char *Tcl_ObjTypeName_ByteArray = "bytearray"; +static Tcl_ObjType *Tcl_ObjType_ByteArray; + +static char *Tcl_ObjTypeName_String = "string"; +static Tcl_ObjType *Tcl_ObjType_String; + +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) +#define IS_TCL_BYTEARRAY(obj) ((obj)->typePtr == Tcl_ObjType_ByteArray) +#define IS_TCL_STRING(obj) ((obj)->typePtr == Tcl_ObjType_String) +#define IS_TCL_VALID_STRING(obj) ((obj)->bytes != (char*)NULL) +#endif +#endif + /* safe Tcl_Eval and Tcl_GlobalEval */ static int +#ifdef RUBY_VM +tcl_eval(Tcl_Interp *interp, const char *cmd) +#else tcl_eval(interp, cmd) Tcl_Interp *interp; const char *cmd; /* don't have to be writable */ +#endif { char *buf = strdup(cmd); int ret; @@ -143,9 +212,13 @@ tcl_eval(interp, cmd) #define Tcl_Eval tcl_eval static int +#ifdef RUBY_VM +tcl_global_eval(Tcl_Interp *interp, const char *cmd) +#else tcl_global_eval(interp, cmd) Tcl_Interp *interp; const char *cmd; /* don't have to be writable */ +#endif { char *buf = strdup(cmd); int ret; @@ -316,12 +389,24 @@ call_queue_mark(struct call_queue *q) static VALUE eventloop_thread; +#ifdef RUBY_VM +Tcl_ThreadId tk_eventloop_thread_id; /* native thread ID of Tcl interpreter */ +#endif static VALUE eventloop_stack; +static int window_event_mode = ~(TCL_WINDOW_EVENTS | TCL_IDLE_EVENTS); static VALUE watchdog_thread; Tcl_Interp *current_interp; - + +/* thread control strategy */ +#define CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE 0 +#define USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0 +#define DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 1 + +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE +static int have_rb_thread_waited_for_value = 0; +#endif /* * 'event_loop_max' is a maximum events which the eventloop processes in one @@ -330,12 +415,27 @@ Tcl_Interp *current_interp; * 'timer_tick' is a limit of one term of thread scheduling. * If 'timer_tick' == 0, then not use the timer for thread scheduling. */ -#define DEFAULT_EVENT_LOOP_MAX 800/*counts*/ -#define DEFAULT_NO_EVENT_TICK 10/*counts*/ -#define DEFAULT_NO_EVENT_WAIT 20/*milliseconds ( 1 -- 999 ) */ -#define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */ -#define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */ -#define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */ +#ifdef RUBY_VM +#define DEFAULT_EVENT_LOOP_MAX 800/*counts*/ +#define DEFAULT_NO_EVENT_TICK 10/*counts*/ +#define DEFAULT_NO_EVENT_WAIT 10/*milliseconds ( 1 -- 999 ) */ +#define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */ +#define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */ +#define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */ +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE +#define DEFAULT_HAS_WAIT_THREAD_TICK 50/*counts*/ +#endif +#else /* ! RUBY_VM */ +#define DEFAULT_EVENT_LOOP_MAX 800/*counts*/ +#define DEFAULT_NO_EVENT_TICK 10/*counts*/ +#define DEFAULT_NO_EVENT_WAIT 20/*milliseconds ( 1 -- 999 ) */ +#define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */ +#define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */ +#define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */ +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE +#define DEFAULT_HAS_WAIT_THREAD_TICK 50/*counts*/ +#endif +#endif static int event_loop_max = DEFAULT_EVENT_LOOP_MAX; static int no_event_tick = DEFAULT_NO_EVENT_TICK; @@ -343,6 +443,9 @@ static int no_event_wait = DEFAULT_NO_EVENT_WAIT; static int timer_tick = DEFAULT_TIMER_TICK; static int req_timer_tick = DEFAULT_TIMER_TICK; static int run_timer_flag = 0; +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE +static int has_wait_thread_tick = DEFAULT_HAS_WAIT_THREAD_TICK; +#endif static int event_loop_wait_event = 0; static int event_loop_abort_on_exc = 1; @@ -569,6 +672,9 @@ struct tcltkip { Tcl_Interp *ip; /* the interpreter */ #if TCL_NAMESPACE_DEBUG Tcl_Namespace *default_ns; /* default namespace */ +#endif +#ifdef RUBY_VM + Tcl_ThreadId tk_thread_id; /* native thread ID of Tcl interpreter */ #endif int has_orig_exit; /* has original 'exit' command ? */ Tcl_CmdInfo orig_exit_info; /* command info of original 'exit' command */ @@ -605,9 +711,9 @@ deleted_ip(ptr) #endif ) { DUMP1("ip is deleted"); - return Qtrue; + return 1; } - return Qfalse; + return 0; } /* increment/decrement reference count of tcltkip */ @@ -760,6 +866,10 @@ tcltkip_init_tk(interp) } #endif +#ifdef RUBY_VM + ptr->tk_thread_id = Tcl_GetCurrentThread(); +#endif + return Qnil; } @@ -767,6 +877,7 @@ tcltkip_init_tk(interp) /* treat excetiopn on Tcl side */ static VALUE rbtk_pending_exception; static int rbtk_eventloop_depth = 0; +static int rbtk_internal_eventloop_handler = 0; static int @@ -776,7 +887,9 @@ pending_exception_check0() if (!NIL_P(exc) && rb_obj_is_kind_of(exc, rb_eException)) { DUMP1("find a pending exception"); - if (rbtk_eventloop_depth > 0) { + if (rbtk_eventloop_depth > 0 + || rbtk_internal_eventloop_handler > 0 + ) { return 1; /* pending */ } else { rbtk_pending_exception = Qnil; @@ -809,7 +922,9 @@ pending_exception_check1(thr_crit_bup, ptr) if (!NIL_P(exc) && rb_obj_is_kind_of(exc, rb_eException)) { DUMP1("find a pending exception"); - if (rbtk_eventloop_depth > 0) { + if (rbtk_eventloop_depth > 0 + || rbtk_internal_eventloop_handler > 0 + ) { return 1; /* pending */ } else { rbtk_pending_exception = Qnil; @@ -867,7 +982,11 @@ call_original_exit(ptr, state) if (info->isNativeObjectProc) { Tcl_Obj **argv; - argv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, 3); + /* argv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, 3); */ /* XXXXXXXXXX */ + argv = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj *) * 3); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ +#endif argv[0] = Tcl_NewStringObj("exit", 4); argv[1] = state_obj; argv[2] = (Tcl_Obj *)NULL; @@ -875,12 +994,24 @@ call_original_exit(ptr, state) ptr->return_value = (*(info->objProc))(info->objClientData, ptr->ip, 2, argv); - free(argv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + /* free(argv); */ + ckfree((char*)argv); +#endif } else { /* string interface */ char **argv; - argv = (char **)ALLOC_N(char *, 3); + /* argv = (char **)ALLOC_N(char *, 3); */ /* XXXXXXXXXX */ + argv = (char **)ckalloc(sizeof(char *) * 3); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ +#endif argv[0] = "exit"; /* argv[1] = Tcl_GetString(state_obj); */ argv[1] = Tcl_GetStringFromObj(state_obj, (int*)NULL); @@ -889,7 +1020,15 @@ call_original_exit(ptr, state) ptr->return_value = (*(info->proc))(info->clientData, ptr->ip, 2, (CONST84 char **)argv); - free(argv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + /* free(argv); */ + ckfree((char*)argv); +#endif } Tcl_DecrRefCount(state_obj); @@ -898,15 +1037,27 @@ call_original_exit(ptr, state) { /* string interface */ char **argv; - argv = (char **)ALLOC_N(char *, 3); + /* argv = (char **)ALLOC_N(char *, 3); */ + argv = (char **)ckalloc(sizeof(char *) * 3); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ +#endif argv[0] = "exit"; - argv[1] = RSTRING(rb_fix2str(INT2NUM(state), 10))->ptr; + argv[1] = RSTRING_PTR(rb_fix2str(INT2NUM(state), 10)); argv[2] = (char *)NULL; ptr->return_value = (*(info->proc))(info->clientData, ptr->ip, 2, argv); - free(argv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + /* free(argv); */ + ckfree(argv); +#endif } #endif @@ -949,6 +1100,49 @@ _timer_for_tcl(clientData) /* tick_counter += event_loop_max; */ } +#ifdef RUBY_VM +#if USE_TOGGLE_WINDOW_MODE_FOR_IDLE +static int +toggle_eventloop_window_mode_for_idle() +{ + if (window_event_mode & TCL_IDLE_EVENTS) { + window_event_mode &= ~TCL_IDLE_EVENTS; + return 1; + } else { + window_event_mode |= TCL_IDLE_EVENTS; + return 0; + } +} +#endif +#endif + +static VALUE +set_eventloop_window_mode(self, mode) + VALUE self; + VALUE mode; +{ + rb_secure(4); + + if (RTEST(mode)) { + window_event_mode = ~0; + } else { + window_event_mode = ~(TCL_WINDOW_EVENTS | TCL_IDLE_EVENTS); + } + + return mode; +} + +static VALUE +get_eventloop_window_mode(self) + VALUE self; +{ + if ( ~window_event_mode ) { + return Qfalse; + } else { + return Qtrue; + } +} + static VALUE set_eventloop_tick(self, tick) VALUE self; @@ -1137,15 +1331,15 @@ set_max_block_time(self, time) case T_BIGNUM: /* time is micro-second value */ divmod = rb_funcall(time, rb_intern("divmod"), 1, LONG2NUM(1000000)); - tcl_time.sec = NUM2LONG(RARRAY(divmod)->ptr[0]); - tcl_time.usec = NUM2LONG(RARRAY(divmod)->ptr[1]); + tcl_time.sec = NUM2LONG(RARRAY_PTR(divmod)[0]); + tcl_time.usec = NUM2LONG(RARRAY_PTR(divmod)[1]); break; case T_FLOAT: /* time is second value */ divmod = rb_funcall(time, rb_intern("divmod"), 1, INT2FIX(1)); - tcl_time.sec = NUM2LONG(RARRAY(divmod)->ptr[0]); - tcl_time.usec = (long)(NUM2DBL(RARRAY(divmod)->ptr[1]) * 1000000); + tcl_time.sec = NUM2LONG(RARRAY_PTR(divmod)[0]); + tcl_time.usec = (long)(NUM2DBL(RARRAY_PTR(divmod)[1]) * 1000000); default: { @@ -1229,8 +1423,10 @@ ip_evloop_abort_on_exc_set(self, val) } static VALUE -lib_num_of_mainwindows(self) +lib_num_of_mainwindows_core(self, argc, argv) VALUE self; + int argc; /* dummy */ + VALUE *argv; /* dummy */ { if (tk_stubs_init_p()) { return INT2FIX(Tk_GetNumMainWindows()); @@ -1239,7 +1435,37 @@ lib_num_of_mainwindows(self) } } +static VALUE +lib_num_of_mainwindows(self) + VALUE self; +{ + return tk_funcall(lib_num_of_mainwindows_core, 0, (VALUE*)NULL, self); +} + + +#ifdef RUBY_VM /* Ruby 1.9+ !!! */ +static VALUE +call_DoOneEvent_core(flag_val) + VALUE flag_val; +{ + int flag; + + flag = FIX2INT(flag_val); + if (Tcl_DoOneEvent(flag)) { + return Qtrue; + } else { + return Qfalse; + } +} + +static VALUE +call_DoOneEvent(flag_val) + VALUE flag_val; +{ + return tk_funcall(call_DoOneEvent_core, 0, (VALUE*)NULL, flag_val); +} +#else /* Ruby 1.8- */ static VALUE call_DoOneEvent(flag_val) VALUE flag_val; @@ -1253,6 +1479,8 @@ call_DoOneEvent(flag_val) return Qfalse; } } +#endif + static VALUE eventloop_sleep(dummy) @@ -1264,22 +1492,77 @@ eventloop_sleep(dummy) t.tv_usec = (time_t)(no_event_wait*1000.0); #ifdef HAVE_NATIVETHREAD +#ifdef RUBY_VM +#if 0 + if (!ruby_native_thread_p()) { + rb_bug("cross-thread violation on eventloop_sleep()"); + } +#endif +#else if (!is_ruby_native_thread()) { rb_bug("cross-thread violation on eventloop_sleep()"); } +#endif #endif + DUMP2("eventloop_sleep: rb_thread_wait_for() at thread : %lx", rb_thread_current()); rb_thread_wait_for(t); + DUMP2("eventloop_sleep: finish at thread : %lx", rb_thread_current()); #ifdef HAVE_NATIVETHREAD +#ifdef RUBY_VM +#if 0 + if (!ruby_native_thread_p()) { + rb_bug("cross-thread violation on eventloop_sleep()"); + } +#endif +#else if (!is_ruby_native_thread()) { rb_bug("cross-thread violation on eventloop_sleep()"); } +#endif #endif return Qnil; } +#define USE_EVLOOP_THREAD_ALONE_CHECK_FLAG 0 + +#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG +static int +get_thread_alone_check_flag() +{ +#ifdef RUBY_VM + return 0; +#else + set_tcltk_version(); + + if (tcltk_version.major < 8) { + /* Tcl/Tk 7.x */ + return 1; + } else if (tcltk_version.major == 8) { + if (tcltk_version.minor < 5) { + /* Tcl/Tk 8.0 - 8.4 */ + return 1; + } else if (tcltk_version.minor == 5) { + if (tcltk_version.type < TCL_FINAL_RELEASE) { + /* Tcl/Tk 8.5a? - 8.5b? */ + return 1; + } else { + /* Tcl/Tk 8.5.x */ + return 0; + } + } else { + /* Tcl/Tk 8.6 - 8.9 ?? */ + return 0; + } + } else { + /* Tcl/Tk 9+ ?? */ + return 0; + } +#endif +} +#endif static int lib_eventloop_core(check_root, update_flag, check_var, interp) @@ -1295,7 +1578,9 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) int thr_crit_bup; int status; int depth = rbtk_eventloop_depth; - +#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG + int thread_alone_check_flag = 1; +#endif if (update_flag) DUMP1("update loop start!!"); @@ -1314,15 +1599,25 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) timer_token = (Tcl_TimerToken)NULL; } +#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG + /* version check */ + thread_alone_check_flag = get_thread_alone_check_flag(); +#endif + for(;;) { +#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG + if (thread_alone_check_flag && rb_thread_alone()) { +#else if (rb_thread_alone()) { +#endif DUMP1("no other thread"); event_loop_wait_event = 0; if (update_flag) { event_flag = update_flag | TCL_DONT_WAIT; /* for safety */ } else { - event_flag = TCL_ALL_EVENTS; + event_flag = TCL_ALL_EVENTS; + /* event_flag = TCL_ALL_EVENTS | TCL_DONT_WAIT; */ } if (timer_tick == 0 && update_flag == 0) { @@ -1349,11 +1644,19 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) if (status) { switch (status) { case TAG_RAISE: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eException, "unknown exception"); } else { +#ifdef RUBY_VM + rbtk_pending_exception = rb_errinfo(); +#else rbtk_pending_exception = ruby_errinfo; +#endif if (!NIL_P(rbtk_pending_exception)) { if (rbtk_eventloop_depth == 0) { @@ -1368,10 +1671,18 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) break; case TAG_FATAL: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif rb_exc_raise(rb_exc_new2(rb_eFatal, "FATAL")); } else { +#ifdef RUBY_VM + rb_exc_raise(rb_errinfo()); +#else rb_exc_raise(ruby_errinfo); +#endif } } } @@ -1462,19 +1773,48 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) if (NIL_P(eventloop_thread) || current == eventloop_thread) { int st; int status; - +#ifdef RUBY_VM + if (update_flag) { + st = RTEST(rb_protect(call_DoOneEvent, + INT2FIX(event_flag), &status)); + } else { + st = RTEST(rb_protect(call_DoOneEvent, + INT2FIX(event_flag & window_event_mode), + &status)); +#if USE_TOGGLE_WINDOW_MODE_FOR_IDLE + if (!st) { + if (toggle_eventloop_window_mode_for_idle()) { + /* idle-mode -> event-mode*/ + tick_counter = 0; + } else { + /* event-mode -> idle-mode */ + tick_counter = event_loop_max; + } + } +#endif + } +#else /* st = Tcl_DoOneEvent(event_flag); */ st = RTEST(rb_protect(call_DoOneEvent, INT2FIX(event_flag), &status)); +#endif if (status) { switch (status) { case TAG_RAISE: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eException, "unknown exception"); } else { +#ifdef RUBY_VM + rbtk_pending_exception = rb_errinfo(); +#else rbtk_pending_exception = ruby_errinfo; +#endif if (!NIL_P(rbtk_pending_exception)) { if (rbtk_eventloop_depth == 0) { @@ -1489,10 +1829,18 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) break; case TAG_FATAL: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif rb_exc_raise(rb_exc_new2(rb_eFatal, "FATAL")); } else { +#ifdef RUBY_VM + rb_exc_raise(rb_errinfo()); +#else rb_exc_raise(ruby_errinfo); +#endif } } } @@ -1525,6 +1873,13 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) return 0; } +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE + if (have_rb_thread_waited_for_value) { + tick_counter += no_event_tick; + have_rb_thread_waited_for_value = 0; + } +#endif + if (st) { tick_counter++; } else { @@ -1536,17 +1891,26 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) tick_counter += no_event_tick; /* rb_thread_wait_for(t); */ + rb_protect(eventloop_sleep, Qnil, &status); if (status) { switch (status) { case TAG_RAISE: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eException, "unknown exception"); } else { +#ifdef RUBY_VM + rbtk_pending_exception = rb_errinfo(); +#else rbtk_pending_exception = ruby_errinfo; +#endif if (!NIL_P(rbtk_pending_exception)) { if (rbtk_eventloop_depth == 0) { @@ -1561,11 +1925,19 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) break; case TAG_FATAL: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif rb_exc_raise(rb_exc_new2(rb_eFatal, "FATAL")); } else { +#ifdef RUBY_VM + rb_exc_raise(rb_errinfo()); +#else rb_exc_raise(ruby_errinfo); +#endif } } } @@ -1619,10 +1991,17 @@ lib_eventloop_core(check_root, update_flag, check_var, interp) break; /* switch to other thread */ } } + + DUMP1("thread scheduling"); + rb_thread_schedule(); } DUMP1("trap check & thread scheduling"); +#ifdef RUBY_VM + /* if (update_flag == 0) CHECK_INTS; */ /*XXXXXXXXXXXXX TODO !!!! */ +#else if (update_flag == 0) CHECK_INTS; +#endif } return 1; @@ -1669,19 +2048,35 @@ lib_eventloop_main(args) switch (status) { case TAG_RAISE: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eException, "unknown exception"); } else { +#ifdef RUBY_VM + rbtk_pending_exception = rb_errinfo(); +#else rbtk_pending_exception = ruby_errinfo; +#endif } return Qnil; case TAG_FATAL: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL"); } else { +#ifdef RUBY_VM + rbtk_pending_exception = rb_errinfo(); +#else rbtk_pending_exception = ruby_errinfo; +#endif } return Qnil; } @@ -1705,6 +2100,7 @@ lib_eventloop_ensure(args) rb_thread_critical = ptr->thr_crit_bup; free(ptr); + /* ckfree((char*)ptr); */ return Qnil; } @@ -1734,9 +2130,16 @@ lib_eventloop_ensure(args) } } +#ifdef RUBY_VM + if (NIL_P(eventloop_thread)) { + tk_eventloop_thread_id = (Tcl_ThreadId) 0; + } +#endif + rb_thread_critical = ptr->thr_crit_bup; free(ptr); + /* ckfree((char*)ptr);*/ DUMP2("finish current eventloop %lx", current_evloop); return Qnil; @@ -1751,10 +2154,14 @@ lib_eventloop_launcher(check_root, update_flag, check_var, interp) { volatile VALUE parent_evloop = eventloop_thread; struct evloop_params *args = ALLOC(struct evloop_params); + /* struct evloop_params *args = (struct evloop_params *)ckalloc(sizeof(struct evloop_params)); */ tcl_stubs_check(); eventloop_thread = rb_thread_current(); +#ifdef RUBY_VM + tk_eventloop_thread_id = Tcl_GetCurrentThread(); +#endif if (parent_evloop == eventloop_thread) { DUMP2("eventloop: recursive call on %lx", parent_evloop); @@ -1905,6 +2312,9 @@ lib_watchdog_ensure(arg) VALUE arg; { eventloop_thread = Qnil; /* stop eventloops */ +#ifdef RUBY_VM + tk_eventloop_thread_id = (Tcl_ThreadId) 0; +#endif return Qnil; } @@ -1916,6 +2326,11 @@ lib_mainloop_watchdog(argc, argv, self) { VALUE check_rootwidget; +#ifdef RUBY_VM + rb_raise(rb_eNotImpError, + "eventloop_watchdog is not implemented on Ruby VM."); +#endif + if (rb_scan_args(argc, argv, "01", &check_rootwidget) == 0) { check_rootwidget = Qtrue; } else if (RTEST(check_rootwidget)) { @@ -2010,8 +2425,10 @@ lib_thread_callback(argc, argv, self) } q = (struct thread_call_proc_arg *)ALLOC(struct thread_call_proc_arg); + /* q = (struct thread_call_proc_arg *)ckalloc(sizeof(struct thread_call_proc_arg)); */ q->proc = proc; q->done = (int*)ALLOC(int); + /* q->done = (int*)ckalloc(sizeof(int)); */ *(q->done) = 0; /* create call-proc thread */ @@ -2032,12 +2449,21 @@ lib_thread_callback(argc, argv, self) free(q->done); free(q); + /* ckfree((char*)q->done); */ + /* ckfree((char*)q); */ if (NIL_P(rbtk_pending_exception)) { +#ifdef RUBY_VM + /* return rb_errinfo(); */ + if (status) { + rb_exc_raise(rb_errinfo()); + } +#else /* return ruby_errinfo; */ if (status) { rb_exc_raise(ruby_errinfo); } +#endif } else { VALUE exc = rbtk_pending_exception; rbtk_pending_exception = Qnil; @@ -2155,28 +2581,33 @@ ip_set_exc_message(interp, exc) if (NIL_P(enc)) { encoding = (Tcl_Encoding)NULL; } else if (TYPE(enc) == T_STRING) { - encoding = Tcl_GetEncoding(interp, RSTRING(enc)->ptr); + encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); } else { enc = rb_funcall(enc, ID_to_s, 0, 0); - encoding = Tcl_GetEncoding(interp, RSTRING(enc)->ptr); + encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); } /* to avoid a garbled error message dialog */ - buf = ALLOC_N(char, (RSTRING(msg)->len)+1); - memcpy(buf, RSTRING(msg)->ptr, RSTRING(msg)->len); - buf[RSTRING(msg)->len] = 0; + /* buf = ALLOC_N(char, (RSTRING(msg)->len)+1);*/ + /* memcpy(buf, RSTRING(msg)->ptr, RSTRING(msg)->len);*/ + /* buf[RSTRING(msg)->len] = 0; */ + buf = ALLOC_N(char, RSTRING_LEN(msg)+1); + /* buf = ckalloc(sizeof(char)*((RSTRING_LEN(msg))+1)); */ + memcpy(buf, RSTRING_PTR(msg), RSTRING_LEN(msg)); + buf[RSTRING_LEN(msg)] = 0; Tcl_DStringInit(&dstr); Tcl_DStringFree(&dstr); - Tcl_ExternalToUtfDString(encoding, buf, RSTRING(msg)->len, &dstr); + Tcl_ExternalToUtfDString(encoding, buf, RSTRING_LEN(msg), &dstr); Tcl_AppendResult(interp, Tcl_DStringValue(&dstr), (char*)NULL); DUMP2("error message:%s", Tcl_DStringValue(&dstr)); Tcl_DStringFree(&dstr); free(buf); + /* ckfree(buf); */ #else /* TCL_VERSION <= 8.0 */ - Tcl_AppendResult(interp, RSTRING(msg)->ptr, (char*)NULL); + Tcl_AppendResult(interp, RSTRING_PTR(msg), (char*)NULL); #endif rb_thread_critical = thr_crit_bup; @@ -2242,58 +2673,104 @@ tcl_protect_core(interp, proc, data) /* should not raise exception */ goto error; error: str = rb_str_new2("LocalJumpError: "); +#ifdef RUBY_VM + rb_str_append(str, rb_obj_as_string(rb_errinfo())); +#else rb_str_append(str, rb_obj_as_string(ruby_errinfo)); +#endif exc = rb_exc_new3(type, str); break; case TAG_RETRY: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif DUMP1("rb_protect: retry"); exc = rb_exc_new2(eTkCallbackRetry, "retry jump error"); } else { +#ifdef RUBY_VM + exc = rb_errinfo(); +#else exc = ruby_errinfo; +#endif } break; case TAG_REDO: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif DUMP1("rb_protect: redo"); exc = rb_exc_new2(eTkCallbackRedo, "redo jump error"); } else { +#ifdef RUBY_VM + exc = rb_errinfo(); +#else exc = ruby_errinfo; +#endif } break; case TAG_RAISE: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif exc = rb_exc_new2(rb_eException, "unknown exception"); } else { +#ifdef RUBY_VM + exc = rb_errinfo(); +#else exc = ruby_errinfo; +#endif } break; case TAG_FATAL: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif exc = rb_exc_new2(rb_eFatal, "FATAL"); } else { +#ifdef RUBY_VM + exc = rb_errinfo(); +#else exc = ruby_errinfo; +#endif } break; case TAG_THROW: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif DUMP1("rb_protect: throw"); exc = rb_exc_new2(eTkCallbackThrow, "throw jump error"); } else { +#ifdef RUBY_VM + exc = rb_errinfo(); +#else exc = ruby_errinfo; +#endif } break; default: buf = ALLOC_N(char, 256); + /* buf = ckalloc(sizeof(char) * 256); */ sprintf(buf, "unknown loncaljmp status %d", status); exc = rb_exc_new2(rb_eException, buf); free(buf); + /* ckfree(buf); */ break; } @@ -2371,12 +2848,12 @@ tcl_protect_core(interp, proc, data) /* should not raise exception */ ret = TkStringValue(ret); DUMP1("Tcl_AppendResult"); - Tcl_AppendResult(interp, RSTRING(ret)->ptr, (char *)NULL); + Tcl_AppendResult(interp, RSTRING_PTR(ret), (char *)NULL); rb_thread_critical = thr_crit_bup; } - DUMP2("(result) %s", NIL_P(ret) ? "nil" : RSTRING(ret)->ptr); + DUMP2("(result) %s", NIL_P(ret) ? "nil" : RSTRING_PTR(ret)); return TCL_OK; } @@ -2391,9 +2868,17 @@ tcl_protect(interp, proc, data) int code; #ifdef HAVE_NATIVETHREAD +#ifdef RUBY_VM +#if 0 + if (!ruby_native_thread_p()) { + rb_bug("cross-thread violation on tcl_protect()"); + } +#endif +#else if (!is_ruby_native_thread()) { rb_bug("cross-thread violation on tcl_protect()"); } +#endif #endif rb_trap_immediate = 0; @@ -2456,6 +2941,7 @@ ip_ruby_eval(clientData, interp, argc, argv) str = Tcl_GetStringFromObj(argv[1], &len); arg = ALLOC_N(char, len + 1); + /* arg = ckalloc(sizeof(char) * (len + 1)); */ memcpy(arg, str, len); arg[len] = 0; @@ -2473,6 +2959,7 @@ ip_ruby_eval(clientData, interp, argc, argv) #if TCL_MAJOR_VERSION >= 8 free(arg); + /* ckfree(arg); */ #endif return code; @@ -2497,6 +2984,96 @@ ip_ruby_cmd_core(arg) return ret; } +#define SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER 1 + +static VALUE +ip_ruby_cmd_receiver_const_get(name) + char *name; +{ + volatile VALUE klass = rb_cObject; + char *head, *tail; + int state; + +#if SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER + klass = rb_eval_string_protect(name, &state); + if (state) { + return Qnil; + } else { + return klass; + } +#else + return rb_const_get(klass, rb_intern(name)); +#endif + + /* TODO!!!!!! */ + /* support nest of classes/modules */ + + /* return rb_eval_string(name); */ + /* return rb_eval_string_protect(name, &state); */ + +#if 0 /* doesn't work!! (fail to autoload?) */ + /* duplicate */ + head = name = strdup(name); + + /* has '::' at head ? */ + if (*head == ':') head += 2; + tail = head; + + /* search */ + while(*tail) { + if (*tail == ':') { + *tail = '\0'; + klass = rb_const_get(klass, rb_intern(head)); + tail += 2; + head = tail; + } else { + tail++; + } + } + + free(name); + return rb_const_get(klass, rb_intern(head)); +#endif +} + +static VALUE +ip_ruby_cmd_receiver_get(str) + char *str; +{ + volatile VALUE receiver; + volatile VALUE klass = rb_cObject; + int state; + + if (str[0] == ':' || ('A' <= str[0] && str[0] <= 'Z')) { + /* class | module | constant */ +#if SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER + receiver = ip_ruby_cmd_receiver_const_get(str); +#else + receiver = rb_protect(ip_ruby_cmd_receiver_const_get, (VALUE)str, &state); + if (state) return Qnil; +#endif + } else if (str[0] == '$') { + /* global variable */ + receiver = rb_gv_get(str); + } else { + /* global variable omitted '$' */ + char *buf; + int len; + + len = strlen(str); + buf = ALLOC_N(char, len + 2); + /* buf = ckalloc(sizeof(char) * (len + 2)); */ + buf[0] = '$'; + memcpy(buf + 1, str, len); + buf[len + 1] = 0; + receiver = rb_gv_get(buf); + free(buf); + /* ckfree(buf); */ + } + + return receiver; +} + /* ruby_cmd receiver method arg ... */ static int #if TCL_MAJOR_VERSION >= 8 @@ -2544,6 +3121,7 @@ ip_ruby_cmd(clientData, interp, argc, argv) /* allocate */ arg = ALLOC(struct cmd_body_arg); + /* arg = (struct cmd_body_arg *)ckalloc(sizeof(struct cmd_body_arg)); */ /* get arguments from Tcl objects */ thr_crit_bup = rb_thread_critical; @@ -2557,24 +3135,8 @@ ip_ruby_cmd(clientData, interp, argc, argv) str = argv[1]; #endif DUMP2("receiver:%s",str); - if (str[0] == ':' || ('A' <= str[0] && str[0] <= 'Z')) { - /* class | module | constant */ - receiver = rb_const_get(rb_cObject, rb_intern(str)); - } else if (str[0] == '$') { - /* global variable */ - receiver = rb_gv_get(str); - } else { - /* global variable omitted '$' */ - char *buf; - - len = strlen(str); - buf = ALLOC_N(char, len + 2); - buf[0] = '$'; - memcpy(buf + 1, str, len); - buf[len + 1] = 0; - receiver = rb_gv_get(buf); - free(buf); - } + /* receiver = rb_protect(ip_ruby_cmd_receiver_get, (VALUE)str, &code); */ + receiver = ip_ruby_cmd_receiver_get(str); if (NIL_P(receiver)) { #if 0 rb_raise(rb_eArgError, @@ -2599,15 +3161,26 @@ ip_ruby_cmd(clientData, interp, argc, argv) /* get args */ args = rb_ary_new2(argc - 2); +#ifdef RUBY_VM +#else RARRAY(args)->len = 0; +#endif for(i = 3; i < argc; i++) { #if TCL_MAJOR_VERSION >= 8 str = Tcl_GetStringFromObj(argv[i], &len); DUMP2("arg:%s",str); +#ifdef RUBY_VM + rb_ary_push(args, rb_tainted_str_new(str, len)); +#else RARRAY(args)->ptr[RARRAY(args)->len++] = rb_tainted_str_new(str, len); +#endif #else /* TCL_MAJOR_VERSION < 8 */ DUMP2("arg:%s",argv[i]); +#ifdef RUBY_VM + rb_ary_push(args, rb_tainted_str_new2(argv[i])); +#else RARRAY(args)->ptr[RARRAY(args)->len++] = rb_tainted_str_new2(argv[i]); +#endif #endif } @@ -2622,6 +3195,7 @@ ip_ruby_cmd(clientData, interp, argc, argv) code = tcl_protect(interp, ip_ruby_cmd_core, (VALUE)arg); free(arg); + /* ckfree((char*)arg); */ return code; } @@ -2799,9 +3373,17 @@ ip_rbUpdateCommand(clientData, interp, objc, objv) return TCL_ERROR; } #ifdef HAVE_NATIVETHREAD +#ifdef RUBY_VM +#if 0 + if (!ruby_native_thread_p()) { + rb_bug("cross-thread violation on ip_ruby_eval()"); + } +#endif +#else if (!is_ruby_native_thread()) { rb_bug("cross-thread violation on ip_ruby_eval()"); } +#endif #endif if (objc == 1) { @@ -2946,9 +3528,17 @@ ip_rb_threadUpdateCommand(clientData, interp, objc, objv) return TCL_ERROR; } #ifdef HAVE_NATIVETHREAD +#ifdef RUBY_VM +#if 0 + if (!ruby_native_thread_p()) { + rb_bug("cross-thread violation on ip_rb_threadUpdateCommand()"); + } +#endif +#else if (!is_ruby_native_thread()) { - rb_bug("cross-thread violation on ip_ruby_eval()"); + rb_bug("cross-thread violation on ip_rb_threadUpdateCommand()"); } +#endif #endif if (rb_thread_alone() @@ -3010,8 +3600,11 @@ ip_rb_threadUpdateCommand(clientData, interp, objc, objv) DUMP1("pass argument check"); - param = (struct th_update_param *)Tcl_Alloc(sizeof(struct th_update_param)); - Tcl_Preserve(param); + /* param = (struct th_update_param *)Tcl_Alloc(sizeof(struct th_update_param)); */ + param = (struct th_update_param *)ckalloc(sizeof(struct th_update_param)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)param); +#endif param->thread = current_thread; param->done = 0; @@ -3023,8 +3616,15 @@ ip_rb_threadUpdateCommand(clientData, interp, objc, objv) rb_thread_stop(); } - Tcl_Release(param); - Tcl_Free((char *)param); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif DUMP1("finish Ruby's 'thread_update'"); return TCL_OK; @@ -3123,9 +3723,17 @@ ip_rbVwaitCommand(clientData, interp, objc, objv) Tcl_Preserve(interp); #ifdef HAVE_NATIVETHREAD +#ifdef RUBY_VM +#if 0 + if (!ruby_native_thread_p()) { + rb_bug("cross-thread violation on ip_rbVwaitCommand()"); + } +#endif +#else if (!is_ruby_native_thread()) { - rb_bug("cross-thread violation on ip_ruby_eval()"); + rb_bug("cross-thread violation on ip_rbVwaitCommand()"); } +#endif #endif if (objc != 2) { @@ -3516,6 +4124,7 @@ ip_rbTkWaitCommand(clientData, interp, objc, objv) thr_crit_bup = rb_thread_critical; rb_thread_critical = Qtrue; + /* This function works on the Tk eventloop thread only. */ if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { window = NULL; } else { @@ -3523,7 +4132,7 @@ ip_rbTkWaitCommand(clientData, interp, objc, objv) } if (window == NULL) { - Tcl_AppendResult(interp, "tkwait: ", + Tcl_AppendResult(interp, ": tkwait: ", "no main-window (not Tk application?)", (char*)NULL); rb_thread_critical = thr_crit_bup; @@ -3612,7 +4221,8 @@ ip_rbTkWaitCommand(clientData, interp, objc, objv) case TKWAIT_WINDOW: thr_crit_bup = rb_thread_critical; rb_thread_critical = Qtrue; - + + /* This function works on the Tk eventloop thread only. */ if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { window = NULL; } else { @@ -3624,7 +4234,7 @@ ip_rbTkWaitCommand(clientData, interp, objc, objv) #endif if (window == NULL) { - Tcl_AppendResult(interp, "tkwait: ", + Tcl_AppendResult(interp, ": tkwait: ", "no main-window (not Tk application?)", (char*)NULL); rb_thread_critical = thr_crit_bup; @@ -3830,8 +4440,11 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv) thr_crit_bup = rb_thread_critical; rb_thread_critical = Qtrue; - param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); - Tcl_Preserve(param); + /* param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); */ + param = (struct th_vwait_param *)ckalloc(sizeof(struct th_vwait_param)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)param); +#endif param->thread = current_thread; param->done = 0; @@ -3849,8 +4462,15 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv) rb_thread_critical = thr_crit_bup; if (ret != TCL_OK) { - Tcl_Release(param); - Tcl_Free((char *)param); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif #if TCL_MAJOR_VERSION >= 8 Tcl_DecrRefCount(objv[1]); @@ -3873,8 +4493,15 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv) rb_threadVwaitProc, (ClientData) param); } - Tcl_Release(param); - Tcl_Free((char *)param); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif rb_thread_critical = thr_crit_bup; @@ -4015,8 +4642,11 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv) nameString = objv[2]; #endif - param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); - Tcl_Preserve(param); + /* param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); */ + param = (struct th_vwait_param *)ckalloc(sizeof(struct th_vwait_param)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)param); +#endif param->thread = current_thread; param->done = 0; @@ -4040,8 +4670,15 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv) rb_thread_critical = thr_crit_bup; if (ret != TCL_OK) { +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ Tcl_Release(param); - Tcl_Free((char *)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif #if TCL_MAJOR_VERSION >= 8 Tcl_DecrRefCount(objv[2]); @@ -4078,21 +4715,42 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv) thr_crit_bup = rb_thread_critical; rb_thread_critical = Qtrue; +#if 0 /* variable 'tkwin' must keep the token of MainWindow */ if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { window = NULL; } else { window = Tk_NameToWindow(interp, nameString, tkwin); } +#else + if (!tk_stubs_init_p() || tkwin == (Tk_Window)NULL) { + window = NULL; + } else { + /* Tk_NameToWindow() returns right token on non-eventloop thread */ + Tcl_CmdInfo info; + if (Tcl_GetCommandInfo(interp, ".", &info)) { /* check root */ + window = Tk_NameToWindow(interp, nameString, tkwin); + } else { + window = NULL; + } + } +#endif if (window == NULL) { - Tcl_AppendResult(interp, "thread_tkwait: ", + Tcl_AppendResult(interp, ": thread_tkwait: ", "no main-window (not Tk application?)", (char*)NULL); rb_thread_critical = thr_crit_bup; +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ Tcl_Release(param); - Tcl_Free((char *)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif #if TCL_MAJOR_VERSION >= 8 Tcl_DecrRefCount(objv[2]); @@ -4141,8 +4799,15 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv) Tcl_Release(window); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ Tcl_Release(param); - Tcl_Free((char *)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif #if TCL_MAJOR_VERSION >= 8 Tcl_DecrRefCount(objv[2]); @@ -4167,25 +4832,46 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv) thr_crit_bup = rb_thread_critical; rb_thread_critical = Qtrue; +#if 0 /* variable 'tkwin' must keep the token of MainWindow */ if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { window = NULL; } else { window = Tk_NameToWindow(interp, nameString, tkwin); } +#else + if (!tk_stubs_init_p() || tkwin == (Tk_Window)NULL) { + window = NULL; + } else { + /* Tk_NameToWindow() returns right token on non-eventloop thread */ + Tcl_CmdInfo info; + if (Tcl_GetCommandInfo(interp, ".", &info)) { /* check root */ + window = Tk_NameToWindow(interp, nameString, tkwin); + } else { + window = NULL; + } + } +#endif #if TCL_MAJOR_VERSION >= 8 Tcl_DecrRefCount(objv[2]); #endif if (window == NULL) { - Tcl_AppendResult(interp, "thread_tkwait: ", + Tcl_AppendResult(interp, ": thread_tkwait: ", "no main-window (not Tk application?)", (char*)NULL); rb_thread_critical = thr_crit_bup; +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ Tcl_Release(param); - Tcl_Free((char *)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif Tcl_Release(tkwin); Tcl_Release(interp); @@ -4224,8 +4910,15 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv) break; } /* end of 'switch' statement */ - Tcl_Release(param); - Tcl_Free((char *)param); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)param); +#endif + /* Tcl_Free((char *)param); */ + ckfree((char *)param); +#endif /* * Clear out the interpreter's result, since it may have been set @@ -4469,6 +5162,18 @@ ip_finalize(ip) #if 1 DUMP1("destroy root widget"); if (tk_stubs_init_p() && Tk_MainWindow(ip) != (Tk_Window)NULL) { + /* + * On Ruby VM, this code piece may be not called, because + * Tk_MainWindow() returns NULL on a native thread except + * the thread which initialize Tk environment. + * Of course, that is a problem. But maybe not so serious. + * All widgets are destroyed when the Tcl interp is deleted. + * At then, Ruby may raise exceptions on the delete hook + * callbacks which registered for the deleted widgets, and + * may fail to clear objects which depends on the widgets. + * Although it is the problem, it is possibly avoidable by + * rescuing exceptions and the finalize hook of the interp. + */ DUMP1("call Tk_DestroyWindow"); ruby_debug = Qfalse; ruby_verbose = Qnil; @@ -4530,13 +5235,15 @@ ip_free(ptr) DUMP2("slave IP(%lx) should not be deleted", (unsigned long)ptr->ip); free(ptr); + /* ckfree((char*)ptr); */ rb_thread_critical = thr_crit_bup; return; } if (ptr->ip == (Tcl_Interp*)NULL) { DUMP1("ip_free is called for deleted IP"); - free(ptr); + /* free(ptr); */ + ckfree((char*)ptr); rb_thread_critical = thr_crit_bup; return; } @@ -4547,6 +5254,7 @@ ip_free(ptr) ptr->ip = (Tcl_Interp*)NULL; free(ptr); + /* ckfree((char*)ptr); */ rb_thread_critical = thr_crit_bup; } @@ -4668,7 +5376,11 @@ ip_rbNamespaceObjCmd(clientData, interp, objc, objv) int i; char **argv; - argv = (char **)Tcl_Alloc(sizeof(char *) * (objc + 1)); + /* argv = (char **)Tcl_Alloc(sizeof(char *) * (objc + 1)); */ + argv = (char **)ckalloc(sizeof(char *) * (objc + 1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ +#endif for(i = 0; i < objc; i++) { /* argv[i] = Tcl_GetString(objv[i]); */ @@ -4679,7 +5391,15 @@ ip_rbNamespaceObjCmd(clientData, interp, objc, objv) ret = (*(info.proc))(info.clientData, interp, objc, (CONST84 char **)argv); - Tcl_Free((char*)argv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + /* Tcl_Free((char*)argv); */ + ckfree((char*)argv); +#endif } DUMP2("namespace wrapper exit depth == %d", rbtk_eventloop_depth); @@ -4750,16 +5470,29 @@ ip_init(argc, argv, self) Tk_Window mainWin = (Tk_Window)NULL; /* security check */ +#ifdef RUBY_VM + if (rb_safe_level() >= 4) { +#else if (ruby_safe_level >= 4) { +#endif rb_raise(rb_eSecurityError, "Cannot create a TclTkIp object at level %d", - ruby_safe_level); +#ifdef RUBY_VM + rb_safe_level() +#else + ruby_safe_level +#endif + ); } /* create object */ Data_Get_Struct(self, struct tcltkip, ptr); ptr = ALLOC(struct tcltkip); + /* ptr = (struct tcltkip *)ckalloc(sizeof(struct tcltkip)); */ DATA_PTR(self) = ptr; +#ifdef RUBY_VM + ptr->tk_thread_id = 0; +#endif ptr->ref_count = 0; ptr->allow_ruby_exit = 1; ptr->return_value = 0; @@ -4867,6 +5600,10 @@ ip_init(argc, argv, self) (Tcl_PackageInitProc *) NULL); #endif +#ifdef RUBY_VM + /* set Tk thread ID */ + ptr->tk_thread_id = Tcl_GetCurrentThread(); +#endif /* get main window */ mainWin = Tk_MainWindow(ptr->ip); Tk_Preserve((ClientData)mainWin); @@ -4942,6 +5679,7 @@ ip_create_slave_core(interp, argc, argv) { struct tcltkip *master = get_ip(interp); struct tcltkip *slave = ALLOC(struct tcltkip); + /* struct tcltkip *slave = (struct tcltkip *)ckalloc(sizeof(struct tcltkip)); */ VALUE safemode; VALUE name; int safe; @@ -4984,6 +5722,10 @@ ip_create_slave_core(interp, argc, argv) #endif /* create slave-ip */ +#ifdef RUBY_VM + /* slave->tk_thread_id = 0; */ + slave->tk_thread_id = master->tk_thread_id; /* == current thread */ +#endif slave->ref_count = 0; slave->allow_ruby_exit = 0; slave->return_value = 0; @@ -5272,6 +6014,12 @@ ip_allow_ruby_exit_set(self, val) "insecure operation on a safe interpreter"); } + /* + * Because of cross-threading, the following line may fail to find + * the MainWindow, even if the Tcl/Tk interpreter has one or more. + * But it has no problem. Current implementation of both type of + * the "exit" command don't need maiinWin token. + */ mainWin = (tk_stubs_init_p())? Tk_MainWindow(ptr->ip): (Tk_Window)NULL; if (RTEST(val)) { @@ -5368,8 +6116,10 @@ ip_is_deleted_p(self) } static VALUE -ip_has_mainwindow_p(self) +ip_has_mainwindow_p_core(self, argc, argv) VALUE self; + int argc; /* dummy */ + VALUE *argv; /* dummy */ { struct tcltkip *ptr = get_ip(self); @@ -5382,6 +6132,14 @@ ip_has_mainwindow_p(self) } } +static VALUE +ip_has_mainwindow_p(self) + VALUE self; +{ + return tk_funcall(ip_has_mainwindow_p_core, 0, (VALUE*)NULL, self); +} + + /*** ruby string <=> tcl object ***/ #if TCL_MAJOR_VERSION >= 8 static VALUE @@ -5391,10 +6149,16 @@ get_str_from_obj(obj) int len, binary = 0; const char *s; volatile VALUE str; +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 4) + int len2; + const char *s2; +#endif #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0 s = Tcl_GetStringFromObj(obj, &len); -#else /* TCL_VERSION >= 8.1 */ +#else +#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 3 + /* TCL_VERSION 8.1 -- 8.3 */ if (Tcl_GetCharLength(obj) != Tcl_UniCharLen(Tcl_GetUnicode(obj))) { /* possibly binary string */ s = Tcl_GetByteArrayFromObj(obj, &len); @@ -5403,9 +6167,30 @@ get_str_from_obj(obj) /* possibly text string */ s = Tcl_GetStringFromObj(obj, &len); } +#else /* TCL_VERSION >= 8.4 */ + if (IS_TCL_BYTEARRAY(obj)) { + s = Tcl_GetByteArrayFromObj(obj, &len); + binary = 1; + } else { + s = Tcl_GetStringFromObj(obj, &len); + } + +#endif #endif str = s ? rb_str_new(s, len) : rb_str_new2(""); - if (binary) rb_ivar_set(str, ID_at_enc, rb_str_new2("binary")); + if (binary) { +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_BINARY); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) + } else { +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_UTF8); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8); +#endif + } return str; } @@ -5416,25 +6201,30 @@ get_obj_from_str(str) const char *s = StringValuePtr(str); #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0 - return Tcl_NewStringObj((char*)s, RSTRING(str)->len); + return Tcl_NewStringObj((char*)s, RSTRING_LEN(str)); #else /* TCL_VERSION >= 8.1 */ VALUE enc = rb_attr_get(str, ID_at_enc); if (!NIL_P(enc)) { StringValue(enc); - if (strcmp(RSTRING(enc)->ptr, "binary") == 0) { + if (strcmp(RSTRING_PTR(enc), "binary") == 0) { /* binary string */ - return Tcl_NewByteArrayObj(s, RSTRING(str)->len); + return Tcl_NewByteArrayObj(s, RSTRING_LEN(str)); } else { /* text string */ - return Tcl_NewStringObj(s, RSTRING(str)->len); + return Tcl_NewStringObj(s, RSTRING_LEN(str)); } - } else if (strlen(s) != RSTRING(str)->len) { +#ifdef RUBY_VM + } else if (rb_enc_get_index(str) == ENCODING_INDEX_BINARY) { + /* binary string */ + return Tcl_NewByteArrayObj(s, RSTRING_LEN(str)); +#endif + } else if (strlen(s) != RSTRING_LEN(str)) { /* probably binary string */ - return Tcl_NewByteArrayObj(s, RSTRING(str)->len); + return Tcl_NewByteArrayObj(s, RSTRING_LEN(str)); } else { /* probably text string */ - return Tcl_NewStringObj(s, RSTRING(str)->len); + return Tcl_NewStringObj(s, RSTRING_LEN(str)); } #endif } @@ -5452,6 +6242,7 @@ ip_get_result_string_obj(interp) Tcl_IncrRefCount(retObj); strval = get_str_from_obj(retObj); OBJ_TAINT(strval); + Tcl_ResetResult(interp); Tcl_DecrRefCount(retObj); return strval; #else @@ -5485,9 +6276,10 @@ call_queue_handler(evPtr, flags) struct tcltkip *ptr; DUMP2("do_call_queue_handler : evPtr = %p", evPtr); - DUMP2("queue_handler thread : %lx", rb_thread_current()); + DUMP2("call_queue_handler thread : %lx", rb_thread_current()); DUMP2("added by thread : %lx", q->thread); + if (*(q->done)) { DUMP1("processed by another event-loop"); return 0; @@ -5505,10 +6297,13 @@ call_queue_handler(evPtr, flags) return 1; } + /* incr internal handler mark */ + rbtk_internal_eventloop_handler++; + /* check safe-level */ if (rb_safe_level() != q->safe_level) { - /* q_dat = Data_Wrap_Struct(rb_cData,0,0,q); */ - q_dat = Data_Wrap_Struct(rb_cData,call_queue_mark,0,q); + /* q_dat = Data_Wrap_Struct(rb_cData,0,-1,q); */ + q_dat = Data_Wrap_Struct(rb_cData,call_queue_mark,-1,q); ret = rb_funcall(rb_proc_new(callq_safelevel_handler, q_dat), ID_call, 0); rb_gc_force_recycle(q_dat); @@ -5519,7 +6314,10 @@ call_queue_handler(evPtr, flags) } /* set result */ - RARRAY(q->result)->ptr[0] = ret; + RARRAY_PTR(q->result)[0] = ret; + + /* decr internal handler mark */ + rbtk_internal_eventloop_handler--; /* complete */ *(q->done) = -1; @@ -5528,8 +6326,16 @@ call_queue_handler(evPtr, flags) if (RTEST(rb_funcall(q->thread, ID_alive_p, 0, 0))) { DUMP2("back to caller (caller thread:%lx)", q->thread); DUMP2(" (current thread:%lx)", rb_thread_current()); +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE + have_rb_thread_waited_for_value = 1; + rb_thread_wakeup(q->thread); +#else rb_thread_run(q->thread); +#endif DUMP1("finish back to caller"); +#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE + rb_thread_schedule(); +#endif } else { DUMP2("caller is dead (caller thread:%lx)", q->thread); DUMP2(" (current thread:%lx)", rb_thread_current()); @@ -5547,19 +6353,39 @@ tk_funcall(func, argc, argv, obj) VALUE obj; { struct call_queue *callq; + struct tcltkip *ptr; int *alloc_done; int thr_crit_bup; + int is_tk_evloop_thread; volatile VALUE current = rb_thread_current(); volatile VALUE ip_obj = obj; volatile VALUE result; volatile VALUE ret; + if (!NIL_P(ip_obj) && rb_obj_is_kind_of(ip_obj, tcltkip_class)) { + ptr = get_ip(ip_obj); + if (deleted_ip(ptr)) return Qnil; + } else { + ptr = (struct tcltkip *)NULL; + } - if (!NIL_P(ip_obj) && deleted_ip(get_ip(ip_obj))) { - return Qnil; +#ifdef RUBY_VM + if (ptr) { + /* on Tcl interpreter */ + is_tk_evloop_thread = (ptr->tk_thread_id == (Tcl_ThreadId) 0 + || ptr->tk_thread_id == Tcl_GetCurrentThread()); + } else { + /* on Tcl/Tk library */ + is_tk_evloop_thread = (tk_eventloop_thread_id == (Tcl_ThreadId) 0 + || tk_eventloop_thread_id == Tcl_GetCurrentThread()); } +#else + is_tk_evloop_thread = 1; +#endif - if (NIL_P(eventloop_thread) || current == eventloop_thread) { + if (is_tk_evloop_thread + && (NIL_P(eventloop_thread) || current == eventloop_thread) + ) { if (NIL_P(eventloop_thread)) { DUMP2("tk_funcall from thread:%lx but no eventloop", current); } else { @@ -5579,23 +6405,32 @@ tk_funcall(func, argc, argv, obj) /* allocate memory (argv cross over thread : must be in heap) */ if (argv) { - VALUE *temp = ALLOC_N(VALUE, argc); + /* VALUE *temp = ALLOC_N(VALUE, argc); */ + VALUE *temp = (VALUE*)ckalloc(sizeof(VALUE) * argc); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)temp); /* XXXXXXXX */ +#endif MEMCPY(temp, argv, VALUE, argc); argv = temp; } /* allocate memory (keep result) */ - alloc_done = (int*)ALLOC(int); + /* alloc_done = (int*)ALLOC(int); */ + alloc_done = (int*)ckalloc(sizeof(int)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */ +#endif *alloc_done = 0; /* allocate memory (freed by Tcl_ServiceEvent) */ - callq = (struct call_queue *)Tcl_Alloc(sizeof(struct call_queue)); + /* callq = (struct call_queue *)Tcl_Alloc(sizeof(struct call_queue)); */ + callq = (struct call_queue *)ckalloc(sizeof(struct call_queue)); +#if 1 /* use Tcl_Preserve/Release */ Tcl_Preserve(callq); +#endif /* allocate result obj */ - result = rb_ary_new2(1); - RARRAY(result)->ptr[0] = Qnil; - RARRAY(result)->len = 1; + result = rb_ary_new3(1, Qnil); /* construct event data */ callq->done = alloc_done; @@ -5610,28 +6445,68 @@ tk_funcall(func, argc, argv, obj) /* add the handler to Tcl event queue */ DUMP1("add handler"); +#ifdef RUBY_VM + if (ptr && ptr->tk_thread_id) { + Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(callq->ev), TCL_QUEUE_HEAD); + Tcl_ThreadAlert(ptr->tk_thread_id); + } else if (tk_eventloop_thread_id) { + Tcl_ThreadQueueEvent(tk_eventloop_thread_id, + &(callq->ev), TCL_QUEUE_HEAD); + Tcl_ThreadAlert(tk_eventloop_thread_id); + } else { + Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD); + } +#else Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD); +#endif rb_thread_critical = thr_crit_bup; /* wait for the handler to be processed */ DUMP2("wait for handler (current thread:%lx)", current); while(*alloc_done >= 0) { - rb_thread_stop(); + DUMP2("*** wait for handler (current thread:%lx)", current); + rb_thread_stop(); + DUMP2("*** wakeup (current thread:%lx)", current); } DUMP2("back from handler (current thread:%lx)", current); /* get result & free allocated memory */ - ret = RARRAY(result)->ptr[0]; - free(alloc_done); - if (argv) free(argv); + ret = RARRAY_PTR(result)[0]; +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */ +#endif + /* free(alloc_done); */ + ckfree((char*)alloc_done); +#endif + /* if (argv) free(argv); */ + if (argv) { + /* if argv != NULL, alloc as 'temp' */ +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + ckfree((char*)argv); +#endif + } +#if 1 /* use Tcl_Preserve/Release */ Tcl_Release(callq); +#else + ckfree((char*)callq); +#endif /* exception? */ if (rb_obj_is_kind_of(ret, rb_eException)) { DUMP1("raise exception"); - rb_exc_raise(ret); + /* rb_exc_raise(ret); */ + rb_exc_raise(rb_exc_new3(rb_obj_class(ret), + rb_funcall(ret, ID_to_s, 0, 0))); } DUMP1("exit tk_funcall"); @@ -5702,19 +6577,35 @@ ip_eval_real(self, cmd_str, cmd_len) ret = rb_protect(call_tcl_eval, (VALUE)&inf, &status); switch(status) { case TAG_RAISE: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eException, "unknown exception"); } else { +#ifdef RUBY_VM + rbtk_pending_exception = rb_errinfo(); +#else rbtk_pending_exception = ruby_errinfo; +#endif } break; case TAG_FATAL: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL"); } else { +#ifdef RUBY_VM + rbtk_pending_exception = rb_errinfo(); +#else rbtk_pending_exception = ruby_errinfo; +#endif } } #endif @@ -5814,6 +6705,11 @@ eval_queue_handler(evPtr, flags) struct eval_queue *q = (struct eval_queue *)evPtr; volatile VALUE ret; volatile VALUE q_dat; + struct tcltkip *ptr; + + DUMP2("do_eval_queue_handler : evPtr = %p", evPtr); + DUMP2("eval_queue_thread : %lx", rb_thread_current()); + DUMP2("added by thread : %lx", q->thread); if (*(q->done)) { DUMP1("processed by another event-loop"); @@ -5825,15 +6721,33 @@ eval_queue_handler(evPtr, flags) /* process it */ *(q->done) = 1; + /* deleted ipterp ? */ + ptr = get_ip(q->interp); + if (deleted_ip(ptr)) { + /* deleted IP --> ignore */ + return 1; + } + + /* incr internal handler mark */ + rbtk_internal_eventloop_handler++; + /* check safe-level */ if (rb_safe_level() != q->safe_level) { #ifdef HAVE_NATIVETHREAD - if (!is_ruby_native_thread()) { - rb_bug("cross-thread violation on eval_queue_handler()"); - } +#ifdef RUBY_VM +#if 0 + if (!ruby_native_thread_p()) { + rb_bug("cross-thread violation on eval_queue_handler()"); + } #endif - /* q_dat = Data_Wrap_Struct(rb_cData,0,0,q); */ - q_dat = Data_Wrap_Struct(rb_cData,eval_queue_mark,0,q); +#else + if (!is_ruby_native_thread()) { + rb_bug("cross-thread violation on eval_queue_handler()"); + } +#endif +#endif + /* q_dat = Data_Wrap_Struct(rb_cData,0,-1,q); */ + q_dat = Data_Wrap_Struct(rb_cData,eval_queue_mark,-1,q); ret = rb_funcall(rb_proc_new(evq_safelevel_handler, q_dat), ID_call, 0); rb_gc_force_recycle(q_dat); @@ -5842,7 +6756,10 @@ eval_queue_handler(evPtr, flags) } /* set result */ - RARRAY(q->result)->ptr[0] = ret; + RARRAY_PTR(q->result)[0] = ret; + + /* decr internal handler mark */ + rbtk_internal_eventloop_handler--; /* complete */ *(q->done) = -1; @@ -5851,8 +6768,16 @@ eval_queue_handler(evPtr, flags) if (RTEST(rb_funcall(q->thread, ID_alive_p, 0, 0))) { DUMP2("back to caller (caller thread:%lx)", q->thread); DUMP2(" (current thread:%lx)", rb_thread_current()); +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE + have_rb_thread_waited_for_value = 1; + rb_thread_wakeup(q->thread); +#else rb_thread_run(q->thread); +#endif DUMP1("finish back to caller"); +#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE + rb_thread_schedule(); +#endif } else { DUMP2("caller is dead (caller thread:%lx)", q->thread); DUMP2(" (current thread:%lx)", rb_thread_current()); @@ -5868,6 +6793,9 @@ ip_eval(self, str) VALUE str; { struct eval_queue *evq; +#ifdef RUBY_VM + struct tcltkip *ptr; +#endif char *eval_str; int *alloc_done; int thr_crit_bup; @@ -5882,13 +6810,23 @@ ip_eval(self, str) StringValue(str); rb_thread_critical = thr_crit_bup; - if (NIL_P(eventloop_thread) || current == eventloop_thread) { +#ifdef RUBY_VM + ptr = get_ip(ip_obj); +#endif + + if ( +#ifdef RUBY_VM + (ptr->tk_thread_id == 0 || ptr->tk_thread_id == Tcl_GetCurrentThread()) + && +#endif + (NIL_P(eventloop_thread) || current == eventloop_thread) + ) { if (NIL_P(eventloop_thread)) { DUMP2("eval from thread:%lx but no eventloop", current); } else { DUMP2("eval from current eventloop %lx", current); } - result = ip_eval_real(self, RSTRING(str)->ptr, RSTRING(str)->len); + result = ip_eval_real(self, RSTRING_PTR(str), RSTRING_LEN(str)); if (rb_obj_is_kind_of(result, rb_eException)) { rb_exc_raise(result); } @@ -5901,26 +6839,35 @@ ip_eval(self, str) rb_thread_critical = Qtrue; /* allocate memory (protected from Tcl_ServiceEvent) */ - alloc_done = (int*)ALLOC(int); + /* alloc_done = (int*)ALLOC(int); */ + alloc_done = (int*)ckalloc(sizeof(int)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */ +#endif *alloc_done = 0; - eval_str = ALLOC_N(char, RSTRING(str)->len + 1); - memcpy(eval_str, RSTRING(str)->ptr, RSTRING(str)->len); - eval_str[RSTRING(str)->len] = 0; + /* eval_str = ALLOC_N(char, RSTRING_LEN(str) + 1); */ + eval_str = ckalloc(sizeof(char) * (RSTRING_LEN(str) + 1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)eval_str); /* XXXXXXXX */ +#endif + memcpy(eval_str, RSTRING_PTR(str), RSTRING_LEN(str)); + eval_str[RSTRING_LEN(str)] = 0; /* allocate memory (freed by Tcl_ServiceEvent) */ - evq = (struct eval_queue *)Tcl_Alloc(sizeof(struct eval_queue)); + /* evq = (struct eval_queue *)Tcl_Alloc(sizeof(struct eval_queue)); */ + evq = (struct eval_queue *)ckalloc(sizeof(struct eval_queue)); +#if 1 /* use Tcl_Preserve/Release */ Tcl_Preserve(evq); +#endif /* allocate result obj */ - result = rb_ary_new2(1); - RARRAY(result)->ptr[0] = Qnil; - RARRAY(result)->len = 1; + result = rb_ary_new3(1, Qnil); /* construct event data */ evq->done = alloc_done; evq->str = eval_str; - evq->len = RSTRING(str)->len; + evq->len = RSTRING_LEN(str); evq->interp = ip_obj; evq->result = result; evq->thread = current; @@ -5931,26 +6878,60 @@ ip_eval(self, str) /* add the handler to Tcl event queue */ DUMP1("add handler"); +#ifdef RUBY_VM + if (ptr->tk_thread_id) { + Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(evq->ev), position); + Tcl_ThreadAlert(ptr->tk_thread_id); + } else { + Tcl_QueueEvent(&(evq->ev), position); + } +#else Tcl_QueueEvent(&(evq->ev), position); +#endif rb_thread_critical = thr_crit_bup; /* wait for the handler to be processed */ DUMP2("wait for handler (current thread:%lx)", current); while(*alloc_done >= 0) { - rb_thread_stop(); + DUMP2("*** wait for handler (current thread:%lx)", current); + rb_thread_stop(); + DUMP2("*** wakeup (current thread:%lx)", current); } DUMP2("back from handler (current thread:%lx)", current); /* get result & free allocated memory */ - ret = RARRAY(result)->ptr[0]; + ret = RARRAY_PTR(result)[0]; - free(alloc_done); - free(eval_str); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */ +#endif + /* free(alloc_done); */ + ckfree((char*)alloc_done); +#endif +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)eval_str, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)eval_str); /* XXXXXXXX */ +#endif + /* free(eval_str); */ + ckfree(eval_str); +#endif +#if 1 /* use Tcl_Preserve/Release */ Tcl_Release(evq); +#else + ckfree((char*)evq); +#endif if (rb_obj_is_kind_of(ret, rb_eException)) { - rb_exc_raise(ret); + DUMP1("raise exception"); + /* rb_exc_raise(ret); */ + rb_exc_raise(rb_exc_new3(rb_obj_class(ret), + rb_funcall(ret, ID_to_s, 0, 0))); } return ret; @@ -6105,7 +7086,12 @@ lib_toUTF8_core(ip_obj, src, encodename) if (NIL_P(encodename)) { if (TYPE(str) == T_STRING) { volatile VALUE enc; + +#ifdef RUBY_VM + enc = rb_funcall(rb_obj_encoding(str), ID_to_s, 0, 0); +#else enc = rb_attr_get(str, ID_at_enc); +#endif if (NIL_P(enc)) { if (NIL_P(ip_obj)) { encoding = (Tcl_Encoding)NULL; @@ -6115,21 +7101,25 @@ lib_toUTF8_core(ip_obj, src, encodename) encoding = (Tcl_Encoding)NULL; } else { StringValue(enc); - encoding = Tcl_GetEncoding(interp, RSTRING(enc)->ptr); + encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); if (encoding == (Tcl_Encoding)NULL) { - rb_warning("Tk-interp has unknown encoding information (@encoding:'%s')", RSTRING(enc)->ptr); + rb_warning("Tk-interp has unknown encoding information (@encoding:'%s')", RSTRING_PTR(enc)); } } } } else { StringValue(enc); - if (strcmp(RSTRING(enc)->ptr, "binary") == 0) { + if (strcmp(RSTRING_PTR(enc), "binary") == 0) { +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_BINARY); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); rb_thread_critical = thr_crit_bup; return str; } - encoding = Tcl_GetEncoding(interp, RSTRING(enc)->ptr); + encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); if (encoding == (Tcl_Encoding)NULL) { - rb_warning("string has unknown encoding information (@encoding:'%s')", RSTRING(enc)->ptr); + rb_warning("string has unknown encoding information (@encoding:'%s')", RSTRING_PTR(enc)); } } } else { @@ -6137,35 +7127,47 @@ lib_toUTF8_core(ip_obj, src, encodename) } } else { StringValue(encodename); - encoding = Tcl_GetEncoding(interp, RSTRING(encodename)->ptr); + if (strcmp(RSTRING_PTR(encodename), "binary") == 0) { +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_BINARY); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); + rb_thread_critical = thr_crit_bup; + return str; + } + encoding = Tcl_GetEncoding(interp, RSTRING_PTR(encodename)); if (encoding == (Tcl_Encoding)NULL) { /* rb_warning("unknown encoding name '%s'", - RSTRING(encodename)->ptr); + RSTRING_PTR(encodename)); */ rb_raise(rb_eArgError, "unknown encoding name '%s'", - RSTRING(encodename)->ptr); + RSTRING_PTR(encodename)); } } StringValue(str); - if (!RSTRING(str)->len) { + if (!RSTRING_LEN(str)) { rb_thread_critical = thr_crit_bup; return str; } - buf = ALLOC_N(char,(RSTRING(str)->len)+1); - memcpy(buf, RSTRING(str)->ptr, RSTRING(str)->len); - buf[RSTRING(str)->len] = 0; + buf = ALLOC_N(char, RSTRING_LEN(str)+1); + /* buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); */ + memcpy(buf, RSTRING_PTR(str), RSTRING_LEN(str)); + buf[RSTRING_LEN(str)] = 0; Tcl_DStringInit(&dstr); Tcl_DStringFree(&dstr); /* Tcl_ExternalToUtfDString(encoding,buf,strlen(buf),&dstr); */ - Tcl_ExternalToUtfDString(encoding, buf, RSTRING(str)->len, &dstr); + Tcl_ExternalToUtfDString(encoding, buf, RSTRING_LEN(str), &dstr); /* str = rb_tainted_str_new2(Tcl_DStringValue(&dstr)); */ /* str = rb_str_new2(Tcl_DStringValue(&dstr)); */ str = rb_str_new(Tcl_DStringValue(&dstr), Tcl_DStringLength(&dstr)); - rb_ivar_set(str, ID_at_enc, rb_tainted_str_new2("utf-8")); +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_UTF8); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8); if (taint_flag) OBJ_TAINT(str); if (encoding != (Tcl_Encoding)NULL) { @@ -6174,6 +7176,7 @@ lib_toUTF8_core(ip_obj, src, encodename) Tcl_DStringFree(&dstr); free(buf); + /* ckfree(buf); */ rb_thread_critical = thr_crit_bup; #endif @@ -6251,10 +7254,21 @@ lib_fromUTF8_core(ip_obj, src, encodename) enc = rb_attr_get(str, ID_at_enc); if (!NIL_P(enc)) { StringValue(enc); - if (strcmp(RSTRING(enc)->ptr, "binary") == 0) { + if (strcmp(RSTRING_PTR(enc), "binary") == 0) { +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_BINARY); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); rb_thread_critical = thr_crit_bup; return str; } +#ifdef RUBY_VM + } else if (rb_enc_get_index(str) == ENCODING_INDEX_BINARY) { + rb_enc_associate_index(str, ENCODING_INDEX_BINARY); + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); + rb_thread_critical = thr_crit_bup; + return str; +#endif } } @@ -6266,9 +7280,9 @@ lib_fromUTF8_core(ip_obj, src, encodename) encoding = (Tcl_Encoding)NULL; } else { StringValue(enc); - encoding = Tcl_GetEncoding(interp, RSTRING(enc)->ptr); + encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); if (encoding == (Tcl_Encoding)NULL) { - rb_warning("Tk-interp has unknown encoding information (@encoding:'%s')", RSTRING(enc)->ptr); + rb_warning("Tk-interp has unknown encoding information (@encoding:'%s')", RSTRING_PTR(enc)); } else { encodename = rb_obj_dup(enc); } @@ -6278,52 +7292,69 @@ lib_fromUTF8_core(ip_obj, src, encodename) } else { StringValue(encodename); - if (strcmp(RSTRING(encodename)->ptr, "binary") == 0) { + if (strcmp(RSTRING_PTR(encodename), "binary") == 0) { char *s; int len; StringValue(str); - s = Tcl_GetByteArrayFromObj(Tcl_NewStringObj(RSTRING(str)->ptr, - RSTRING(str)->len), + s = Tcl_GetByteArrayFromObj(Tcl_NewStringObj(RSTRING_PTR(str), + RSTRING_LEN(str)), &len); str = rb_tainted_str_new(s, len); - rb_ivar_set(str, ID_at_enc, rb_tainted_str_new2("binary")); +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_BINARY); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); rb_thread_critical = thr_crit_bup; return str; } - encoding = Tcl_GetEncoding(interp, RSTRING(encodename)->ptr); + encoding = Tcl_GetEncoding(interp, RSTRING_PTR(encodename)); if (encoding == (Tcl_Encoding)NULL) { /* rb_warning("unknown encoding name '%s'", - RSTRING(encodename)->ptr); + RSTRING_PTR(encodename)); encodename = Qnil; */ rb_raise(rb_eArgError, "unknown encoding name '%s'", - RSTRING(encodename)->ptr); + RSTRING_PTR(encodename)); } } StringValue(str); - if (RSTRING(str)->len == 0) { + if (RSTRING_LEN(str) == 0) { rb_thread_critical = thr_crit_bup; return rb_tainted_str_new2(""); } - buf = ALLOC_N(char,strlen(RSTRING(str)->ptr)+1); - memcpy(buf, RSTRING(str)->ptr, RSTRING(str)->len); - buf[RSTRING(str)->len] = 0; + buf = ALLOC_N(char, RSTRING_LEN(str)+1); + /* buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); */ + memcpy(buf, RSTRING_PTR(str), RSTRING_LEN(str)); + buf[RSTRING_LEN(str)] = 0; Tcl_DStringInit(&dstr); Tcl_DStringFree(&dstr); /* Tcl_UtfToExternalDString(encoding,buf,strlen(buf),&dstr); */ - Tcl_UtfToExternalDString(encoding,buf,RSTRING(str)->len,&dstr); + Tcl_UtfToExternalDString(encoding,buf,RSTRING_LEN(str),&dstr); /* str = rb_tainted_str_new2(Tcl_DStringValue(&dstr)); */ /* str = rb_str_new2(Tcl_DStringValue(&dstr)); */ str = rb_str_new(Tcl_DStringValue(&dstr), Tcl_DStringLength(&dstr)); +#ifdef RUBY_VM + if (interp) { + /* can access encoding_table of TclTkIp */ + /* -> try to use encoding_table */ + VALUE tbl = ip_get_encoding_table(ip_obj); + VALUE encobj = encoding_table_get_obj(tbl, encodename); + rb_enc_associate_index(str, rb_to_encoding_index(encobj)); + } else { + /* cannot access encoding_table of TclTkIp */ + /* -> try to find on Ruby Encoding */ + rb_enc_associate_index(str, rb_enc_find_index(RSTRING_PTR(encodename))); + } +#endif rb_ivar_set(str, ID_at_enc, encodename); if (taint_flag) OBJ_TAINT(str); @@ -6334,6 +7365,7 @@ lib_fromUTF8_core(ip_obj, src, encodename) Tcl_DStringFree(&dstr); free(buf); + /* ckfree(buf); */ rb_thread_critical = thr_crit_bup; #endif @@ -6384,21 +7416,29 @@ lib_UTF_backslash_core(self, str, all_bs) tcl_stubs_check(); StringValue(str); - if (!RSTRING(str)->len) { + if (!RSTRING_LEN(str)) { return str; } thr_crit_bup = rb_thread_critical; rb_thread_critical = Qtrue; - src_buf = ALLOC_N(char,(RSTRING(str)->len)+1); - memcpy(src_buf, RSTRING(str)->ptr, RSTRING(str)->len); - src_buf[RSTRING(str)->len] = 0; + /* src_buf = ALLOC_N(char, RSTRING_LEN(str)+1); */ + src_buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)src_buf); /* XXXXXXXX */ +#endif + memcpy(src_buf, RSTRING_PTR(str), RSTRING_LEN(str)); + src_buf[RSTRING_LEN(str)] = 0; - dst_buf = ALLOC_N(char,(RSTRING(str)->len)+1); + /* dst_buf = ALLOC_N(char, RSTRING_LEN(str)+1); */ + dst_buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)dst_buf); /* XXXXXXXX */ +#endif ptr = src_buf; - while(RSTRING(str)->len > ptr - src_buf) { + while(RSTRING_LEN(str) > ptr - src_buf) { if (*ptr == '\\' && (all_bs || *(ptr + 1) == 'u')) { dst_len += Tcl_UtfBackslash(ptr, &read_len, (dst_buf + dst_len)); ptr += read_len; @@ -6409,9 +7449,29 @@ lib_UTF_backslash_core(self, str, all_bs) str = rb_str_new(dst_buf, dst_len); if (taint_flag) OBJ_TAINT(str); +#ifdef RUBY_VM + rb_enc_associate_index(str, ENCODING_INDEX_UTF8); +#endif + rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8); - free(src_buf); - free(dst_buf); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)src_buf, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)src_buf); /* XXXXXXXX */ +#endif + /* free(src_buf); */ + ckfree(src_buf); +#endif +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)dst_buf, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)dst_buf); /* XXXXXXXX */ +#endif + /* free(dst_buf); */ + ckfree(dst_buf); +#endif rb_thread_critical = thr_crit_bup; #endif @@ -6464,7 +7524,7 @@ lib_set_system_encoding(self, enc_name) if (Tcl_SetSystemEncoding((Tcl_Interp *)NULL, StringValuePtr(enc_name)) != TCL_OK) { rb_raise(rb_eArgError, "unknown encoding name '%s'", - RSTRING(enc_name)->ptr); + RSTRING_PTR(enc_name)); } return enc_name; @@ -6502,7 +7562,11 @@ invoke_tcl_proc(arg) #if TCL_MAJOR_VERSION >= 8 if (!inf->cmdinfo.isNativeObjectProc) { /* string interface */ - argv = (char **)ALLOC_N(char *, argc+1); + /* argv = (char **)ALLOC_N(char *, argc+1);*/ /* XXXXXXXXXX */ + argv = (char **)ckalloc(sizeof(char *)*(argc+1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ +#endif for (i = 0; i < argc; ++i) { argv[i] = Tcl_GetStringFromObj(inf->objv[i], &len); } @@ -6527,7 +7591,15 @@ invoke_tcl_proc(arg) = (*(inf->cmdinfo.proc))(inf->cmdinfo.clientData, inf->ptr->ip, argc, (CONST84 char **)argv); - free(argv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + /* free(argv); */ + ckfree((char*)argv); +#endif #else /* TCL_MAJOR_VERSION < 8 */ inf->ptr->return_value @@ -6573,6 +7645,9 @@ ip_invoke_core(interp, argc, argv) #endif #endif + /* get the data struct */ + ptr = get_ip(interp); + /* get the command name string */ #if TCL_MAJOR_VERSION >= 8 cmd = Tcl_GetStringFromObj(objv[0], &len); @@ -6632,14 +7707,22 @@ ip_invoke_core(interp, argc, argv) unknown_flag = 1; #if TCL_MAJOR_VERSION >= 8 - unknown_objv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, objc+2); + /* unknown_objv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, objc+2); */ + unknown_objv = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj *) * (objc+2)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)unknown_objv); /* XXXXXXXX */ +#endif unknown_objv[0] = Tcl_NewStringObj("::unknown", 9); Tcl_IncrRefCount(unknown_objv[0]); memcpy(unknown_objv + 1, objv, sizeof(Tcl_Obj *)*objc); unknown_objv[++objc] = (Tcl_Obj*)NULL; objv = unknown_objv; #else - unknown_argv = (char **)ALLOC_N(char *, argc+2); + /* unknown_argv = (char **)ALLOC_N(char *, argc+2); */ + unknown_argv = (char **)ckalloc(sizeof(char *) * (argc+2)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)unknown_argv); /* XXXXXXXX */ +#endif unknown_argv[0] = strdup("unknown"); memcpy(unknown_argv + 1, argv, sizeof(char *)*argc); unknown_argv[++argc] = (char *)NULL; @@ -6652,7 +7735,6 @@ ip_invoke_core(interp, argc, argv) thr_crit_bup = rb_thread_critical; rb_thread_critical = Qtrue; - #if 1 /* wrap tcl-proc call */ /* setup params */ inf.ptr = ptr; @@ -6669,19 +7751,35 @@ ip_invoke_core(interp, argc, argv) ret = rb_protect(invoke_tcl_proc, (VALUE)&inf, &status); switch(status) { case TAG_RAISE: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eException, "unknown exception"); } else { +#ifdef RUBY_VM + rbtk_pending_exception = rb_errinfo(); +#else rbtk_pending_exception = ruby_errinfo; +#endif } break; case TAG_FATAL: +#ifdef RUBY_VM + if (NIL_P(rb_errinfo())) { +#else if (NIL_P(ruby_errinfo)) { +#endif rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL"); } else { +#ifdef RUBY_VM + rbtk_pending_exception = rb_errinfo(); +#else rbtk_pending_exception = ruby_errinfo; +#endif } } @@ -6693,7 +7791,11 @@ ip_invoke_core(interp, argc, argv) int i; /* string interface */ - argv = (char **)ALLOC_N(char *, argc+1); + /* argv = (char **)ALLOC_N(char *, argc+1); */ + argv = (char **)ckalloc(sizeof(char *) * (argc+1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ +#endif for (i = 0; i < argc; ++i) { argv[i] = Tcl_GetStringFromObj(objv[i], &len); } @@ -6722,7 +7824,15 @@ ip_invoke_core(interp, argc, argv) ptr->return_value = (*info.proc)(info.clientData, ptr->ip, argc, (CONST84 char **)argv); - free(argv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + /* free(argv); */ + ckfree((char*)argv); +#endif #else /* TCL_MAJOR_VERSION < 8 */ ptr->return_value = (*info.proc)(info.clientData, ptr->ip, @@ -6735,10 +7845,27 @@ ip_invoke_core(interp, argc, argv) if (unknown_flag) { #if TCL_MAJOR_VERSION >= 8 Tcl_DecrRefCount(objv[0]); - free(objv); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)objv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)objv); /* XXXXXXXX */ +#endif + /* free(objv); */ + ckfree((char*)objv); +#endif #else free(argv[0]); - free(argv); + /* ckfree(argv[0]); */ +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)argv); /* XXXXXXXX */ +#endif + /* free(argv); */ + ckfree((char*)argv); +#endif #endif } @@ -6793,7 +7920,11 @@ alloc_invoke_arguments(argc, argv) /* memory allocation */ #if TCL_MAJOR_VERSION >= 8 - av = ALLOC_N(Tcl_Obj *, argc+1); + /* av = ALLOC_N(Tcl_Obj *, argc+1);*/ /* XXXXXXXXXX */ + av = (Tcl_Obj**)ckalloc(sizeof(Tcl_Obj *)*(argc+1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)av); /* XXXXXXXX */ +#endif for (i = 0; i < argc; ++i) { av[i] = get_obj_from_str(argv[i]); Tcl_IncrRefCount(av[i]); @@ -6802,7 +7933,11 @@ alloc_invoke_arguments(argc, argv) #else /* TCL_MAJOR_VERSION < 8 */ /* string interface */ - av = ALLOC_N(char *, argc+1); + /* av = ALLOC_N(char *, argc+1); */ + av = (char**)ckalloc(sizeof(char *) * (argc+1)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)av); /* XXXXXXXX */ +#endif for (i = 0; i < argc; ++i) { av[i] = strdup(StringValuePtr(argv[i])); } @@ -6832,7 +7967,26 @@ free_invoke_arguments(argc, av) free(av[i]); #endif } - free(av); +#if TCL_MAJOR_VERSION >= 8 +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)av, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)av); /* XXXXXXXX */ +#endif + ckfree((char*)av); +#endif +#else /* TCL_MAJOR_VERSION < 8 */ +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)av, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)av); /* XXXXXXXX */ +#endif + /* free(av); */ + ckfree((char*)av); +#endif +#endif } static VALUE @@ -6895,6 +8049,7 @@ invoke_queue_handler(evPtr, flags) struct invoke_queue *q = (struct invoke_queue *)evPtr; volatile VALUE ret; volatile VALUE q_dat; + struct tcltkip *ptr; DUMP2("do_invoke_queue_handler : evPtr = %p", evPtr); DUMP2("invoke queue_thread : %lx", rb_thread_current()); @@ -6910,10 +8065,20 @@ invoke_queue_handler(evPtr, flags) /* process it */ *(q->done) = 1; + /* deleted ipterp ? */ + ptr = get_ip(q->interp); + if (deleted_ip(ptr)) { + /* deleted IP --> ignore */ + return 1; + } + + /* incr internal handler mark */ + rbtk_internal_eventloop_handler++; + /* check safe-level */ if (rb_safe_level() != q->safe_level) { /* q_dat = Data_Wrap_Struct(rb_cData,0,0,q); */ - q_dat = Data_Wrap_Struct(rb_cData,invoke_queue_mark,0,q); + q_dat = Data_Wrap_Struct(rb_cData,invoke_queue_mark,-1,q); ret = rb_funcall(rb_proc_new(ivq_safelevel_handler, q_dat), ID_call, 0); rb_gc_force_recycle(q_dat); @@ -6924,7 +8089,10 @@ invoke_queue_handler(evPtr, flags) } /* set result */ - RARRAY(q->result)->ptr[0] = ret; + RARRAY_PTR(q->result)[0] = ret; + + /* decr internal handler mark */ + rbtk_internal_eventloop_handler--; /* complete */ *(q->done) = -1; @@ -6933,8 +8101,16 @@ invoke_queue_handler(evPtr, flags) if (RTEST(rb_funcall(q->thread, ID_alive_p, 0, 0))) { DUMP2("back to caller (caller thread:%lx)", q->thread); DUMP2(" (current thread:%lx)", rb_thread_current()); +#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE + have_rb_thread_waited_for_value = 1; + rb_thread_wakeup(q->thread); +#else rb_thread_run(q->thread); +#endif DUMP1("finish back to caller"); +#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE + rb_thread_schedule(); +#endif } else { DUMP2("caller is dead (caller thread:%lx)", q->thread); DUMP2(" (current thread:%lx)", rb_thread_current()); @@ -6952,6 +8128,9 @@ ip_invoke_with_position(argc, argv, obj, position) Tcl_QueuePosition position; { struct invoke_queue *ivq; +#ifdef RUBY_VM + struct tcltkip *ptr; +#endif int *alloc_done; int thr_crit_bup; volatile VALUE current = rb_thread_current(); @@ -6968,7 +8147,21 @@ ip_invoke_with_position(argc, argv, obj, position) if (argc < 1) { rb_raise(rb_eArgError, "command name missing"); } - if (NIL_P(eventloop_thread) || current == eventloop_thread) { + +#ifdef RUBY_VM + ptr = get_ip(ip_obj); + DUMP2("status: ptr->tk_thread_id %d", ptr->tk_thread_id); +#endif + DUMP2("status: Tcl_GetCurrentThread %d", Tcl_GetCurrentThread()); + DUMP2("status: eventloopt_thread %lx", eventloop_thread); + + if ( +#ifdef RUBY_VM + (ptr->tk_thread_id == 0 || ptr->tk_thread_id == Tcl_GetCurrentThread()) + && +#endif + (NIL_P(eventloop_thread) || current == eventloop_thread) + ) { if (NIL_P(eventloop_thread)) { DUMP2("invoke from thread:%lx but no eventloop", current); } else { @@ -6990,17 +8183,22 @@ ip_invoke_with_position(argc, argv, obj, position) av = alloc_invoke_arguments(argc, argv); /* allocate memory (keep result) */ - alloc_done = (int*)ALLOC(int); + /* alloc_done = (int*)ALLOC(int); */ + alloc_done = (int*)ckalloc(sizeof(int)); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */ +#endif *alloc_done = 0; /* allocate memory (freed by Tcl_ServiceEvent) */ - ivq = (struct invoke_queue *)Tcl_Alloc(sizeof(struct invoke_queue)); - Tcl_Preserve(ivq); + /* ivq = (struct invoke_queue *)Tcl_Alloc(sizeof(struct invoke_queue)); */ + ivq = (struct invoke_queue *)ckalloc(sizeof(struct invoke_queue)); +#if 1 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)ivq); /* XXXXXXXX */ +#endif /* allocate result obj */ - result = rb_ary_new2(1); - RARRAY(result)->ptr[0] = Qnil; - RARRAY(result)->len = 1; + result = rb_ary_new3(1, Qnil); /* construct event data */ ivq->done = alloc_done; @@ -7014,7 +8212,16 @@ ip_invoke_with_position(argc, argv, obj, position) /* add the handler to Tcl event queue */ DUMP1("add handler"); +#ifdef RUBY_VM + if (ptr->tk_thread_id) { + Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(ivq->ev), position); + Tcl_ThreadAlert(ptr->tk_thread_id); + } else { + Tcl_QueueEvent(&(ivq->ev), position); + } +#else Tcl_QueueEvent(&(ivq->ev), position); +#endif rb_thread_critical = thr_crit_bup; @@ -7027,9 +8234,25 @@ ip_invoke_with_position(argc, argv, obj, position) /* get result & free allocated memory */ ret = RARRAY(result)->ptr[0]; - free(alloc_done); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */ +#endif + /* free(alloc_done); */ + ckfree((char*)alloc_done); +#endif +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)ivq, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 1 /* use Tcl_Preserve/Release */ Tcl_Release(ivq); +#else + ckfree((char*)ivq); +#endif +#endif /* free allocated memory */ free_invoke_arguments(argc, av); @@ -7037,7 +8260,9 @@ ip_invoke_with_position(argc, argv, obj, position) /* exception? */ if (rb_obj_is_kind_of(ret, rb_eException)) { DUMP1("raise exception"); - rb_exc_raise(ret); + /* rb_exc_raise(ret); */ + rb_exc_raise(rb_exc_new3(rb_obj_class(ret), + rb_funcall(ret, ID_to_s, 0, 0))); } DUMP1("exit ip_invoke"); @@ -7119,8 +8344,8 @@ ip_get_variable2_core(interp, argc, argv) } else { /* Tcl_Preserve(ptr->ip); */ rbtk_preserve_ip(ptr); - ret = Tcl_GetVar2Ex(ptr->ip, RSTRING(varname)->ptr, - NIL_P(index) ? NULL : RSTRING(index)->ptr, + ret = Tcl_GetVar2Ex(ptr->ip, RSTRING_PTR(varname), + NIL_P(index) ? NULL : RSTRING_PTR(index), FIX2INT(flag)); } @@ -7157,8 +8382,8 @@ ip_get_variable2_core(interp, argc, argv) } else { /* Tcl_Preserve(ptr->ip); */ rbtk_preserve_ip(ptr); - ret = Tcl_GetVar2(ptr->ip, RSTRING(varname)->ptr, - NIL_P(index) ? NULL : RSTRING(index)->ptr, + ret = Tcl_GetVar2(ptr->ip, RSTRING_PTR(varname), + NIL_P(index) ? NULL : RSTRING_PTR(index), FIX2INT(flag)); } @@ -7256,8 +8481,8 @@ ip_set_variable2_core(interp, argc, argv) } else { /* Tcl_Preserve(ptr->ip); */ rbtk_preserve_ip(ptr); - ret = Tcl_SetVar2Ex(ptr->ip, RSTRING(varname)->ptr, - NIL_P(index) ? NULL : RSTRING(index)->ptr, + ret = Tcl_SetVar2Ex(ptr->ip, RSTRING_PTR(varname), + NIL_P(index) ? NULL : RSTRING_PTR(index), valobj, FIX2INT(flag)); } @@ -7297,9 +8522,9 @@ ip_set_variable2_core(interp, argc, argv) } else { /* Tcl_Preserve(ptr->ip); */ rbtk_preserve_ip(ptr); - ret = Tcl_SetVar2(ptr->ip, RSTRING(varname)->ptr, - NIL_P(index) ? NULL : RSTRING(index)->ptr, - RSTRING(value)->ptr, FIX2INT(flag)); + ret = Tcl_SetVar2(ptr->ip, RSTRING_PTR(varname), + NIL_P(index) ? NULL : RSTRING_PTR(index), + RSTRING_PTR(value), FIX2INT(flag)); } if (ret == (char*)NULL) { @@ -7379,8 +8604,8 @@ ip_unset_variable2_core(interp, argc, argv) return Qtrue; } - ptr->return_value = Tcl_UnsetVar2(ptr->ip, RSTRING(varname)->ptr, - NIL_P(index) ? NULL : RSTRING(index)->ptr, + ptr->return_value = Tcl_UnsetVar2(ptr->ip, RSTRING_PTR(varname), + NIL_P(index) ? NULL : RSTRING_PTR(index), FIX2INT(flag)); if (ptr->return_value == TCL_ERROR) { @@ -7500,6 +8725,10 @@ lib_split_tklist_core(ip_obj, list_str) volatile VALUE ary, elem; int idx; int taint_flag = OBJ_TAINTED(list_str); +#ifdef RUBY_VM + int list_enc_idx; + volatile VALUE list_ivar_enc; +#endif int result; VALUE old_gc; @@ -7514,6 +8743,10 @@ lib_split_tklist_core(ip_obj, list_str) } StringValue(list_str); +#ifdef RUBY_VM + list_enc_idx = rb_enc_get_index(list_str); + list_ivar_enc = rb_ivar_get(list_str, ID_at_enc); +#endif { #if TCL_MAJOR_VERSION >= 8 @@ -7552,11 +8785,21 @@ lib_split_tklist_core(ip_obj, list_str) for(idx = 0; idx < objc; idx++) { elem = get_str_from_obj(objv[idx]); +#ifdef RUBY_VM + if (rb_enc_get_index(elem) == ENCODING_INDEX_BINARY) { + rb_enc_associate_index(elem, ENCODING_INDEX_BINARY); + rb_ivar_set(elem, ID_at_enc, ENCODING_NAME_BINARY); + } else { + rb_enc_associate_index(elem, list_enc_idx); + rb_ivar_set(elem, ID_at_enc, list_ivar_enc); + } +#endif if (taint_flag) OBJ_TAINT(elem); - RARRAY(ary)->ptr[idx] = elem; + /* RARRAY(ary)->ptr[idx] = elem; */ + rb_ary_push(ary, elem); } - RARRAY(ary)->len = objc; + /* RARRAY(ary)->len = objc; */ if (old_gc == Qfalse) rb_gc_enable(); @@ -7573,7 +8816,7 @@ lib_split_tklist_core(ip_obj, list_str) int argc; char **argv; - if (Tcl_SplitList(interp, RSTRING(list_str)->ptr, + if (Tcl_SplitList(interp, RSTRING_PTR(list_str), &argc, &argv) == TCL_ERROR) { if (interp == (Tcl_Interp*)NULL) { rb_raise(rb_eRuntimeError, "can't get elements from list"); @@ -7594,9 +8837,10 @@ lib_split_tklist_core(ip_obj, list_str) elem = rb_str_new2(argv[idx]); } /* rb_ivar_set(elem, ID_at_enc, rb_str_new2("binary")); */ - RARRAY(ary)->ptr[idx] = elem; + /* RARRAY(ary)->ptr[idx] = elem; */ + rb_ary_push(ary, elem) } - RARRAY(ary)->len = argc; + /* RARRAY(ary)->len = argc; */ if (old_gc == Qfalse) rb_gc_enable(); #endif @@ -7645,7 +8889,11 @@ lib_merge_tklist(argc, argv, obj) old_gc = rb_gc_disable(); /* based on Tcl/Tk's Tcl_Merge() */ - flagPtr = ALLOC_N(int, argc); + /* flagPtr = ALLOC_N(int, argc); */ + flagPtr = (int *)ckalloc(sizeof(int) * argc); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)flagPtr); /* XXXXXXXXXX */ +#endif /* pass 1 */ len = 1; @@ -7653,7 +8901,7 @@ lib_merge_tklist(argc, argv, obj) if (OBJ_TAINTED(argv[num])) taint_flag = 1; dst = StringValuePtr(argv[num]); #if TCL_MAJOR_VERSION >= 8 - len += Tcl_ScanCountedElement(dst, RSTRING(argv[num])->len, + len += Tcl_ScanCountedElement(dst, RSTRING_LEN(argv[num]), &flagPtr[num]) + 1; #else /* TCL_MAJOR_VERSION < 8 */ len += Tcl_ScanElement(dst, &flagPtr[num]) + 1; @@ -7661,15 +8909,19 @@ lib_merge_tklist(argc, argv, obj) } /* pass 2 */ - result = (char *)Tcl_Alloc(len); + /* result = (char *)Tcl_Alloc(len); */ + result = (char *)ckalloc(len); +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Preserve((ClientData)result); +#endif dst = result; for(num = 0; num < argc; num++) { #if TCL_MAJOR_VERSION >= 8 - len = Tcl_ConvertCountedElement(RSTRING(argv[num])->ptr, - RSTRING(argv[num])->len, + len = Tcl_ConvertCountedElement(RSTRING_PTR(argv[num]), + RSTRING_LEN(argv[num]), dst, flagPtr[num]); #else /* TCL_MAJOR_VERSION < 8 */ - len = Tcl_ConvertElement(RSTRING(argv[num])->ptr, dst, flagPtr[num]); + len = Tcl_ConvertElement(RSTRING_PTR(argv[num]), dst, flagPtr[num]); #endif dst += len; *dst = ' '; @@ -7681,12 +8933,28 @@ lib_merge_tklist(argc, argv, obj) dst[-1] = 0; } - free(flagPtr); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)flagPtr, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)flagPtr); +#endif + /* free(flagPtr); */ + ckfree((char*)flagPtr); +#endif /* create object */ str = rb_str_new(result, dst - result - 1); if (taint_flag) OBJ_TAINT(str); - Tcl_Free(result); +#if 0 /* use Tcl_EventuallyFree */ + Tcl_EventuallyFree((ClientData)result, TCL_DYNAMIC); /* XXXXXXXX */ +#else +#if 0 /* use Tcl_Preserve/Release */ + Tcl_Release((ClientData)result); /* XXXXXXXXXXX */ +#endif + /* Tcl_Free(result); */ + ckfree(result); +#endif if (old_gc == Qfalse) rb_gc_enable(); rb_thread_critical = thr_crit_bup; @@ -7712,19 +8980,18 @@ lib_conv_listelement(self, src) StringValue(src); #if TCL_MAJOR_VERSION >= 8 - len = Tcl_ScanCountedElement(RSTRING(src)->ptr, RSTRING(src)->len, + len = Tcl_ScanCountedElement(RSTRING_PTR(src), RSTRING_LEN(src), &scan_flag); dst = rb_str_new(0, len + 1); - len = Tcl_ConvertCountedElement(RSTRING(src)->ptr, RSTRING(src)->len, - RSTRING(dst)->ptr, scan_flag); + len = Tcl_ConvertCountedElement(RSTRING_PTR(src), RSTRING_LEN(src), + RSTRING_PTR(dst), scan_flag); #else /* TCL_MAJOR_VERSION < 8 */ - len = Tcl_ScanElement(RSTRING(src)->ptr, &scan_flag); + len = Tcl_ScanElement(RSTRING_PTR(src), &scan_flag); dst = rb_str_new(0, len + 1); - len = Tcl_ConvertElement(RSTRING(src)->ptr, RSTRING(dst)->ptr, scan_flag); + len = Tcl_ConvertElement(RSTRING_PTR(src), RSTRING_PTR(dst), scan_flag); #endif - RSTRING(dst)->len = len; - RSTRING(dst)->ptr[len] = '\0'; + rb_str_resize(dst, len); if (taint_flag) OBJ_TAINT(dst); rb_thread_critical = thr_crit_bup; @@ -7732,6 +8999,34 @@ lib_conv_listelement(self, src) return dst; } +static VALUE +lib_getversion(self) + VALUE self; +{ + volatile VALUE type_name; + + set_tcltk_version(); + + switch(tcltk_version.type) { + case TCL_ALPHA_RELEASE: + type_name = rb_str_new2("alpha"); + break; + case TCL_BETA_RELEASE: + type_name = rb_str_new2("beta"); + break; + case TCL_FINAL_RELEASE: + type_name = rb_str_new2("final"); + break; + default: + type_name = rb_str_new2("unknown"); + } + + return rb_ary_new3(5, INT2NUM(tcltk_version.major), + INT2NUM(tcltk_version.minor), + INT2NUM(tcltk_version.type), type_name, + INT2NUM(tcltk_version.patchlevel)); +} + static VALUE tcltklib_compile_info() @@ -7754,6 +9049,7 @@ tcltklib_compile_info() + strlen("unknown tcl_threads"); info = ALLOC_N(char, size); + /* info = ckalloc(sizeof(char) * size); */ /* SEGV */ sprintf(info, form, TCLTKLIB_RELEASE_DATE, @@ -7789,15 +9085,532 @@ tcltklib_compile_info() ret = rb_obj_freeze(rb_str_new2(info)); free(info); + /* ckfree(info); */ return ret; } + +/*###############################################*/ + +static VALUE +create_dummy_encoding_for_tk_core(interp, name, error_mode) + VALUE interp; + VALUE name; + VALUE error_mode; +{ + struct tcltkip *ptr = get_ip(interp); + + rb_secure(4); + + StringValue(name); + +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) + if (Tcl_GetEncoding(ptr->ip, RSTRING_PTR(name)) == (Tcl_Encoding) NULL) { + if (RTEST(error_mode)) { + rb_raise(rb_eArgError, "invalid Tk encoding name '%s'", + RSTRING_PTR(name)); + } else { + return Qnil; + } + } +#endif + +#ifdef RUBY_VM + if (RTEST(rb_define_dummy_encoding(RSTRING_PTR(name)))) { + int idx = rb_enc_find_index(StringValueCStr(name)); + return rb_enc_from_encoding(rb_enc_from_index(idx)); + } else { + if (RTEST(error_mode)) { + rb_raise(rb_eRuntimeError, "fail to create dummy encoding for '%s'", + RSTRING_PTR(name)); + } else { + return Qnil; + } + } +#else + return name; +#endif +} +static VALUE +create_dummy_encoding_for_tk(interp, name) + VALUE interp; + VALUE name; +{ + return create_dummy_encoding_for_tk_core(interp, name, Qtrue); +} + + +#ifdef RUBY_VM +static int +update_encoding_table(table, interp, error_mode) + VALUE table; + VALUE interp; + VALUE error_mode; +{ + struct tcltkip *ptr; + int retry = 0; + int i, idx, objc; + Tcl_Obj **objv; + Tcl_Obj *enc_list; + volatile VALUE encname = Qnil; + volatile VALUE encobj = Qnil; + + /* interpreter check */ + if (NIL_P(interp)) return 0; + ptr = get_ip(interp); + if (ptr == (struct tcltkip *) NULL) return 0; + if (deleted_ip(ptr)) return 0; + + /* get Tcl's encoding list */ + Tcl_GetEncodingNames(ptr->ip); + enc_list = Tcl_GetObjResult(ptr->ip); + Tcl_IncrRefCount(enc_list); + + if (Tcl_ListObjGetElements(ptr->ip, enc_list, + &objc, &objv) != TCL_OK) { + Tcl_DecrRefCount(enc_list); + /* rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names");*/ + return 0; + } + + /* check each encoding name */ + for(i = 0; i < objc; i++) { + encname = rb_str_new2(Tcl_GetString(objv[i])); + if (NIL_P(rb_hash_lookup(table, encname))) { + /* new Tk encoding -> add to table */ + idx = rb_enc_find_index(StringValueCStr(encname)); + if (idx < 0) { + encobj = create_dummy_encoding_for_tk_core(interp,encname,error_mode); + } else { + encobj = rb_enc_from_encoding(rb_enc_from_index(idx)); + } + encname = rb_obj_freeze(encname); + rb_hash_aset(table, encname, encobj); + if (!NIL_P(encobj) && NIL_P(rb_hash_lookup(table, encobj))) { + rb_hash_aset(table, encobj, encname); + } + retry = 1; + } + } + + Tcl_DecrRefCount(enc_list); + + return retry; +} + +static VALUE +encoding_table_get_name_core(table, enc_arg, error_mode) + VALUE table; + VALUE enc_arg; + VALUE error_mode; +{ + volatile VALUE enc = enc_arg; + volatile VALUE name = Qnil; + volatile VALUE tmp = Qnil; + volatile VALUE interp = rb_ivar_get(table, ID_at_interp); + struct tcltkip *ptr = (struct tcltkip *) NULL; + int idx; + + /* deleted interp ? */ + if (!NIL_P(interp)) { + ptr = get_ip(interp); + if (deleted_ip(ptr)) { + ptr = (struct tcltkip *) NULL; + } + } + + /* encoding argument check */ + /* 1st: default encoding setting of interp */ + if (ptr && NIL_P(enc)) { + if (rb_respond_to(interp, ID_encoding_name)) { + enc = rb_funcall(interp, ID_encoding_name, 0, 0); + } + } + /* 2nd: encoding system of Tcl/Tk */ + if (NIL_P(enc)) { + enc = rb_str_new2(Tcl_GetEncodingName((Tcl_Encoding)NULL)); + } + /* 3rd: Encoding.default_external */ + if (NIL_P(enc)) { + enc = rb_enc_default_external(); + } + + if (RTEST(rb_obj_is_kind_of(enc, cRubyEncoding))) { + /* Ruby's Encoding object */ + name = rb_hash_lookup(table, enc); + if (!NIL_P(name)) { + /* find */ + return name; + } + + /* is it new ? */ + /* update check of Tk encoding names */ + if (update_encoding_table(table, interp, error_mode)) { + /* add new relations to the table */ + /* RETRY: registered Ruby encoding? */ + name = rb_hash_lookup(table, enc); + if (!NIL_P(name)) { + /* find */ + return name; + } + } + /* fail to find */ + + } else { + /* String or Symbol? */ + name = rb_funcall(enc, ID_to_s, 0, 0); + + if (!NIL_P(rb_hash_lookup(table, name))) { + /* find */ + return name; + } + + /* is it new ? */ + idx = rb_enc_find_index(StringValueCStr(name)); + if (idx >= 0) { + enc = rb_enc_from_encoding(rb_enc_from_index(idx)); + + /* registered Ruby encoding? */ + tmp = rb_hash_lookup(table, enc); + if (!NIL_P(tmp)) { + /* find */ + return tmp; + } + + /* update check of Tk encoding names */ + if (update_encoding_table(table, interp, error_mode)) { + /* add new relations to the table */ + /* RETRY: registered Ruby encoding? */ + tmp = rb_hash_lookup(table, enc); + if (!NIL_P(tmp)) { + /* find */ + return tmp; + } + } + } + /* fail to find */ + } + + if (RTEST(error_mode)) { + enc = rb_funcall(enc_arg, ID_to_s, 0, 0); + rb_raise(rb_eArgError, "unsupported Tk encoding '%s'", RSTRING_PTR(enc)); + } + return Qnil; +} +static VALUE +encoding_table_get_obj_core(table, enc, error_mode) + VALUE table; + VALUE enc; + VALUE error_mode; +{ + volatile VALUE obj = Qnil; + + obj = rb_hash_lookup(table, + encoding_table_get_name_core(table, enc, error_mode)); + if (RTEST(rb_obj_is_kind_of(obj, cRubyEncoding))) { + return obj; + } else { + return Qnil; + } +} + +#else /* ! RUBY_VM */ +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) +static int +update_encoding_table(table, interp, error_mode) + VALUE table; + VALUE interp; + VALUE error_mode; +{ + struct tcltkip *ptr; + int retry = 0; + int i, idx, objc; + Tcl_Obj **objv; + Tcl_Obj *enc_list; + volatile VALUE encname = Qnil; + volatile VALUE encobj = Qnil; + + /* interpreter check */ + if (NIL_P(interp)) return 0; + ptr = get_ip(interp); + if (ptr == (struct tcltkip *) NULL) return 0; + if (deleted_ip(ptr)) return 0; + + /* get Tcl's encoding list */ + Tcl_GetEncodingNames(ptr->ip); + enc_list = Tcl_GetObjResult(ptr->ip); + Tcl_IncrRefCount(enc_list); + + if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) { + Tcl_DecrRefCount(enc_list); + /* rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names"); */ + return 0; + } + + /* get encoding name and set it to table */ + for(i = 0; i < objc; i++) { + encname = rb_str_new2(Tcl_GetString(objv[i])); + if (NIL_P(rb_hash_lookup(table, encname))) { + /* new Tk encoding -> add to table */ + encname = rb_obj_freeze(encname); + rb_hash_aset(table, encname, encname); + retry = 1; + } + } + + Tcl_DecrRefCount(enc_list); + + return retry; +} + +static VALUE +encoding_table_get_name_core(table, enc, error_mode) + VALUE table; + VALUE enc; + VALUE error_mode; +{ + volatile VALUE name = Qnil; + int retry = 0; + + enc = rb_funcall(enc, ID_to_s, 0, 0); + name = rb_hash_lookup(table, enc); + + if (!NIL_P(name)) { + /* find */ + return name; + } + + /* update check */ + if (update_encoding_table(table, rb_ivar_get(table, ID_at_interp), + error_mode)) { + /* add new relations to the table */ + /* RETRY: registered Ruby encoding? */ + name = rb_hash_lookup(table, enc); + if (!NIL_P(name)) { + /* find */ + return name; + } + } + + if (RTEST(error_mode)) { + rb_raise(rb_eArgError, "unsupported Tk encoding '%s'", RSTRING_PTR(enc)); + } + return Qnil; +} +static VALUE +encoding_table_get_obj_core(table, enc, error_mode) + VALUE table; + VALUE enc; + VALUE error_mode; +{ + return encoding_table_get_name_core(table, enc, error_mode); +} + +#else /* Tcl/Tk 7.x or 8.0 */ +static VALUE +encoding_table_get_name_core(table, enc, error_mode) + VALUE table; + VALUE enc; + VALUE error_mode; +{ + return Qnil; +} +static VALUE +encoding_table_get_obj_core(table, enc, error_mode) + VALUE table; + VALUE enc; + VALUE error_mode; +{ + return Qnil; +} +#endif /* end of dependency for the version of Tcl/Tk */ +#endif + +static VALUE +encoding_table_get_name(table, enc) + VALUE table; + VALUE enc; +{ + return encoding_table_get_name_core(table, enc, Qtrue); +} +static VALUE +encoding_table_get_obj(table, enc) + VALUE table; + VALUE enc; +{ + return encoding_table_get_obj_core(table, enc, Qtrue); +} + +#ifdef RUBY_VM +static VALUE +create_encoding_table(interp) + VALUE interp; +{ + struct tcltkip *ptr = get_ip(interp); + volatile VALUE table = rb_hash_new(); + volatile VALUE encname = Qnil; + volatile VALUE encobj = Qnil; + int i, idx, objc; + Tcl_Obj **objv; + Tcl_Obj *enc_list; + + rb_secure(4); + + /* set 'binary' encoding */ + encobj = rb_enc_from_encoding(rb_enc_from_index(ENCODING_INDEX_BINARY)); + rb_hash_aset(table, ENCODING_NAME_BINARY, encobj); + rb_hash_aset(table, encobj, ENCODING_NAME_BINARY); + + + /* Tcl stub check */ + tcl_stubs_check(); + + /* get Tcl's encoding list */ + Tcl_GetEncodingNames(ptr->ip); + enc_list = Tcl_GetObjResult(ptr->ip); + Tcl_IncrRefCount(enc_list); + + if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) { + Tcl_DecrRefCount(enc_list); + rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names"); + } + + /* get encoding name and set it to table */ + for(i = 0; i < objc; i++) { + int name2obj, obj2name; + + name2obj = 1; obj2name = 1; + encname = rb_obj_freeze(rb_str_new2(Tcl_GetString(objv[i]))); + idx = rb_enc_find_index(StringValueCStr(encname)); + if (idx < 0) { + /* fail to find ruby encoding -> check known encoding */ + if (strcmp(RSTRING_PTR(encname), "identity") == 0) { + name2obj = 1; obj2name = 0; + idx = ENCODING_INDEX_BINARY; + + } else if (strcmp(RSTRING_PTR(encname), "shiftjis") == 0) { + name2obj = 1; obj2name = 0; + idx = rb_enc_find_index("Shift_JIS"); + + } else if (strcmp(RSTRING_PTR(encname), "unicode") == 0) { + name2obj = 1; obj2name = 0; + idx = ENCODING_INDEX_UTF8; + + } else if (strcmp(RSTRING_PTR(encname), "symbol") == 0) { + name2obj = 1; obj2name = 0; + idx = rb_enc_find_index("ASCII-8BIT"); + + } else { + /* regist dummy encoding */ + name2obj = 1; obj2name = 1; + } + } + + if (idx < 0) { + /* unknown encoding -> create dummy */ + encobj = create_dummy_encoding_for_tk(interp, encname); + } else { + encobj = rb_enc_from_encoding(rb_enc_from_index(idx)); + } + + if (name2obj) { + DUMP2("create_encoding_table: name2obj: %s", RSTRING_PTR(encname)); + rb_hash_aset(table, encname, encobj); + } + if (obj2name) { + DUMP2("create_encoding_table: obj2name: %s", RSTRING_PTR(encname)); + rb_hash_aset(table, encobj, encname); + } + } + + Tcl_DecrRefCount(enc_list); + + rb_ivar_set(table, ID_at_interp, interp); + rb_ivar_set(interp, ID_encoding_table, table); + + return table; +} + +#else /* ! RUBY_VM */ +#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) +static VALUE +create_encoding_table(interp) + VALUE interp; +{ + struct tcltkip *ptr = get_ip(interp); + volatile VALUE table = rb_hash_new(); + volatile VALUE encname = Qnil; + int i, objc; + Tcl_Obj **objv; + Tcl_Obj *enc_list; + + rb_secure(4); + + /* set 'binary' encoding */ + rb_hash_aset(table, ENCODING_NAME_BINARY, ENCODING_NAME_BINARY); + + /* get Tcl's encoding list */ + Tcl_GetEncodingNames(ptr->ip); + enc_list = Tcl_GetObjResult(ptr->ip); + Tcl_IncrRefCount(enc_list); + + if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) { + Tcl_DecrRefCount(enc_list); + rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names"); + } + + /* get encoding name and set it to table */ + for(i = 0; i < objc; i++) { + encname = rb_obj_freeze(rb_str_new2(Tcl_GetString(objv[i]))); + rb_hash_aset(table, encname, encname); + } + + Tcl_DecrRefCount(enc_list); + + rb_ivar_set(table, ID_at_interp, interp); + rb_ivar_set(interp, ID_encoding_table, table); + + return table; +} + +#else /* Tcl/Tk 7.x or 8.0 */ +static VALUE +create_encoding_table(interp) + VALUE interp; +{ + volatile VALUE table = rb_hash_new(); + rb_secure(4); + rb_ivar_set(interp, ID_encoding_table, table); + return table; +} +#endif +#endif + +static VALUE +ip_get_encoding_table(interp) + VALUE interp; +{ + volatile VALUE table = Qnil; + + table = rb_ivar_get(interp, ID_encoding_table); + + if (NIL_P(table)) { + /* initialize encoding_table */ + table = create_encoding_table(interp); + rb_define_singleton_method(table, "get_name", encoding_table_get_name, 1); + rb_define_singleton_method(table, "get_obj", encoding_table_get_obj, 1); + } + + return table; +} + + /*###############################################*/ /* * The following is based on tkMenu.[ch] - * of Tcl/Tk (>=8.0) source code. + * of Tcl/Tk (Tk8.0 -- Tk8.5b1) source code. */ #if TCL_MAJOR_VERSION >= 8 @@ -7831,22 +9644,45 @@ struct dummy_TkMenuRef { char *dummy3; }; +#if 0 /* was available on Tk8.0 -- Tk8.4 */ EXTERN struct dummy_TkMenuRef *TkFindMenuReferences(Tcl_Interp*, char*); +#else /* based on Tk8.0 -- Tk8.5.0 */ +#define MENU_HASH_KEY "tkMenus" +#endif #endif static VALUE -ip_make_menu_embeddable(interp, menu_path) +ip_make_menu_embeddable_core(interp, argc, argv) VALUE interp; - VALUE menu_path; + int argc; + VALUE *argv; { #if TCL_MAJOR_VERSION >= 8 + volatile VALUE menu_path; struct tcltkip *ptr = get_ip(interp); - struct dummy_TkMenuRef *menuRefPtr; + struct dummy_TkMenuRef *menuRefPtr = NULL; + XEvent event; + Tcl_HashTable *menuTablePtr; + Tcl_HashEntry *hashEntryPtr; + menu_path = argv[0]; StringValue(menu_path); - menuRefPtr = TkFindMenuReferences(ptr->ip, RSTRING(menu_path)->ptr); +#if 0 /* was available on Tk8.0 -- Tk8.4 */ + menuRefPtr = TkFindMenuReferences(ptr->ip, RSTRING_PTR(menu_path)); +#else /* based on Tk8.0 -- Tk8.5b1 */ + if ((menuTablePtr + = (Tcl_HashTable *) Tcl_GetAssocData(ptr->ip, MENU_HASH_KEY, NULL)) + != NULL) { + if ((hashEntryPtr + = Tcl_FindHashEntry(menuTablePtr, RSTRING_PTR(menu_path))) + != NULL) { + menuRefPtr = (struct dummy_TkMenuRef *) Tcl_GetHashValue(hashEntryPtr); + } + } +#endif + if (menuRefPtr == (struct dummy_TkMenuRef *) NULL) { rb_raise(rb_eArgError, "not a menu widget, or invalid widget path"); } @@ -7873,9 +9709,20 @@ ip_make_menu_embeddable(interp, menu_path) } #endif +#if 0 /* was available on Tk8.0 -- Tk8.4 */ TkEventuallyRecomputeMenu(menuRefPtr->menuPtr); TkEventuallyRedrawMenu(menuRefPtr->menuPtr, (struct dummy_TkMenuEntry *)NULL); +#else /* based on Tk8.0 -- Tk8.5b1 */ + memset((void *) &event, 0, sizeof(event)); + event.xany.type = ConfigureNotify; + event.xany.serial = NextRequest(Tk_Display((menuRefPtr->menuPtr)->tkwin)); + event.xany.send_event = 0; /* FALSE */ + event.xany.window = Tk_WindowId((menuRefPtr->menuPtr)->tkwin); + event.xany.display = Tk_Display((menuRefPtr->menuPtr)->tkwin); + event.xconfigure.window = event.xany.window; + Tk_HandleEvent(&event); +#endif #else /* TCL_MAJOR_VERSION <= 7 */ rb_notimplement(); @@ -7884,6 +9731,18 @@ ip_make_menu_embeddable(interp, menu_path) return interp; } +static VALUE +ip_make_menu_embeddable(interp, menu_path) + VALUE interp; + VALUE menu_path; +{ + VALUE argv[1]; + + argv[0] = menu_path; + return tk_funcall(ip_make_menu_embeddable_core, 1, argv, interp); +} + + /*###############################################*/ /*---- initialization ----*/ @@ -7897,6 +9756,7 @@ Init_tcltklib() VALUE ev_flag = rb_define_module_under(lib, "EventFlag"); VALUE var_flag = rb_define_module_under(lib, "VarAccessFlag"); + VALUE release_type = rb_define_module_under(lib, "RELEASE_TYPE"); /* --------------------------------------------------------------- */ @@ -7904,6 +9764,22 @@ Init_tcltklib() /* --------------------------------------------------------------- */ +#ifdef RUBY_VM + rb_global_variable(&cRubyEncoding); + cRubyEncoding = rb_const_get(rb_cObject, rb_intern("Encoding")); + + ENCODING_INDEX_UTF8 = rb_enc_to_index(rb_utf8_encoding()); + ENCODING_INDEX_BINARY = rb_enc_find_index("binary"); +#endif + + rb_global_variable(&ENCODING_NAME_UTF8); + rb_global_variable(&ENCODING_NAME_BINARY); + + ENCODING_NAME_UTF8 = rb_obj_freeze(rb_str_new2("utf-8")); + ENCODING_NAME_BINARY = rb_obj_freeze(rb_str_new2("binary")); + + /* --------------------------------------------------------------- */ + rb_global_variable(&eTkCallbackReturn); rb_global_variable(&eTkCallbackBreak); rb_global_variable(&eTkCallbackContinue); @@ -7954,6 +9830,14 @@ Init_tcltklib() /* --------------------------------------------------------------- */ + rb_define_module_function(lib, "get_version", lib_getversion, -1); + + rb_define_const(release_type, "ALPHA", INT2FIX(TCL_ALPHA_RELEASE)); + rb_define_const(release_type, "BETA", INT2FIX(TCL_BETA_RELEASE)); + rb_define_const(release_type, "FINAL", INT2FIX(TCL_FINAL_RELEASE)); + + /* --------------------------------------------------------------- */ + eTkCallbackReturn = rb_define_class("TkCallbackReturn", rb_eStandardError); eTkCallbackBreak = rb_define_class("TkCallbackBreak", rb_eStandardError); eTkCallbackContinue = rb_define_class("TkCallbackContinue", @@ -7973,6 +9857,8 @@ Init_tcltklib() ID_at_enc = rb_intern("@encoding"); ID_at_interp = rb_intern("@interp"); + ID_encoding_name = rb_intern("encoding_name"); + ID_encoding_table = rb_intern("encoding_table"); ID_stop_p = rb_intern("stop?"); ID_alive_p = rb_intern("alive?"); @@ -8006,6 +9892,10 @@ Init_tcltklib() lib_evloop_abort_on_exc, 0); rb_define_module_function(lib, "mainloop_abort_on_exception=", lib_evloop_abort_on_exc_set, 1); + rb_define_module_function(lib, "set_eventloop_window_mode", + set_eventloop_window_mode, 1); + rb_define_module_function(lib, "get_eventloop_window_mode", + get_eventloop_window_mode, 0); rb_define_module_function(lib, "set_eventloop_tick",set_eventloop_tick,1); rb_define_module_function(lib, "get_eventloop_tick",get_eventloop_tick,0); rb_define_module_function(lib, "set_no_event_wait", set_no_event_wait, 1); @@ -8067,6 +9957,12 @@ Init_tcltklib() /* --------------------------------------------------------------- */ + rb_define_method(ip, "create_dummy_encoding_for_tk", + create_dummy_encoding_for_tk, 1); + rb_define_method(ip, "encoding_table", ip_get_encoding_table, 0); + + /* --------------------------------------------------------------- */ + rb_define_method(ip, "_get_variable", ip_get_variable, 2); rb_define_method(ip, "_get_variable2", ip_get_variable2, 3); rb_define_method(ip, "_set_variable", ip_set_variable, 3); @@ -8126,7 +10022,11 @@ Init_tcltklib() /* if ruby->nativethread-supprt and tcltklib->doen't, the following will cause link-error. */ +#ifdef RUBY_VM + ruby_native_thread_p(); +#else is_ruby_native_thread(); +#endif /* --------------------------------------------------------------- */ @@ -8134,7 +10034,7 @@ Init_tcltklib() /* --------------------------------------------------------------- */ - ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0); + ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0); switch(ret) { case TCLTK_STUBS_OK: break; @@ -8147,6 +10047,11 @@ Init_tcltklib() } /* --------------------------------------------------------------- */ + + Tcl_ObjType_ByteArray = Tcl_GetObjType(Tcl_ObjTypeName_ByteArray); + Tcl_ObjType_String = Tcl_GetObjType(Tcl_ObjTypeName_String); + + /* --------------------------------------------------------------- */ } /* eof */ diff --git a/ext/tk/tkutil/extconf.rb b/ext/tk/tkutil/extconf.rb index dd00d5d535..51f775619c 100644 --- a/ext/tk/tkutil/extconf.rb +++ b/ext/tk/tkutil/extconf.rb @@ -7,5 +7,6 @@ end if has_tk require 'mkmf' + have_func("rb_obj_instance_exec", "ruby.h") create_makefile('tkutil') end diff --git a/ext/tk/tkutil/tkutil.c b/ext/tk/tkutil/tkutil.c index f4271a724c..1781dd5e4a 100644 --- a/ext/tk/tkutil/tkutil.c +++ b/ext/tk/tkutil/tkutil.c @@ -3,17 +3,24 @@ tkutil.c - $Author$ - $Date$ created at: Fri Nov 3 00:47:54 JST 1995 ************************************************/ -#define TKUTIL_RELEASE_DATE "2006-04-06" +#define TKUTIL_RELEASE_DATE "2008-03-29" #include "ruby.h" + +#ifdef RUBY_VM /* Ruby 1.9 */ +/* #include "ruby/ruby.h" */ +#include "ruby/signal.h" +#include "ruby/st.h" +#else +/* #include "ruby.h" */ #include "rubysig.h" #include "version.h" #include "st.h" +#endif static VALUE cMethod; @@ -27,6 +34,8 @@ static VALUE TK_None; static VALUE cCB_SUBST; static VALUE cSUBST_INFO; +static VALUE ENCODING_NAME_UTF8; /* for saving GC cost */ + static ID ID_split_tklist; static ID ID_toUTF8; static ID ID_fromUTF8; @@ -59,7 +68,7 @@ tk_s_new(argc, argv, klass) VALUE obj = rb_class_new_instance(argc, argv, klass); if (rb_block_given_p()) { -#if RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR <= 8 /* ruby 1.8.x */ +#ifndef HAVE_RB_OBJ_INSTANCE_EXEC rb_obj_instance_eval(0, 0, obj); #else rb_obj_instance_exec(1, &obj, obj); @@ -155,16 +164,16 @@ tk_uninstall_cmd(self, cmd_id) int prefix_len = strlen(cmd_id_prefix); StringValue(cmd_id); - if (strncmp(cmd_id_head, RSTRING(cmd_id)->ptr, head_len) != 0) { + if (strncmp(cmd_id_head, RSTRING_PTR(cmd_id), head_len) != 0) { return Qnil; } if (strncmp(cmd_id_prefix, - RSTRING(cmd_id)->ptr + head_len, prefix_len) != 0) { + RSTRING_PTR(cmd_id) + head_len, prefix_len) != 0) { return Qnil; } return rb_hash_delete(CALLBACK_TABLE, - rb_str_new2(RSTRING(cmd_id)->ptr + head_len)); + rb_str_new2(RSTRING_PTR(cmd_id) + head_len)); } static VALUE @@ -227,7 +236,7 @@ tk_symbolkey2str(self, keys) if NIL_P(keys) return new_keys; keys = rb_convert_type(keys, T_HASH, "Hash", "to_hash"); - st_foreach(RHASH(keys)->tbl, to_strkey, new_keys); + st_foreach(RHASH_TBL(keys), to_strkey, new_keys); return new_keys; } @@ -267,25 +276,24 @@ ary2list(ary, enc_flag, self) req_chk_flag = 0; } - /* size = RARRAY(ary)->len; */ + /* size = RARRAY_LEN(ary); */ size = 0; - for(idx = 0; idx < RARRAY(ary)->len; idx++) { - if (TYPE(RARRAY(ary)->ptr[idx]) == T_HASH) { - size += 2 * RHASH(RARRAY(ary)->ptr[idx])->tbl->num_entries; + for(idx = 0; idx < RARRAY_LEN(ary); idx++) { + if (TYPE(RARRAY_PTR(ary)[idx]) == T_HASH) { + size += 2 * RHASH_SIZE(RARRAY_PTR(ary)[idx]); } else { size++; } } dst = rb_ary_new2(size); - RARRAY(dst)->len = 0; - for(idx = 0; idx < RARRAY(ary)->len; idx++) { - val = RARRAY(ary)->ptr[idx]; + for(idx = 0; idx < RARRAY_LEN(ary); idx++) { + val = RARRAY_PTR(ary)[idx]; str_val = Qnil; switch(TYPE(val)) { case T_ARRAY: str_val = ary2list(val, enc_flag, self); - RARRAY(dst)->ptr[RARRAY(dst)->len++] = str_val; + rb_ary_push(dst, str_val); if (req_chk_flag) { str_enc = rb_ivar_get(str_val, ID_at_enc); @@ -303,19 +311,19 @@ ary2list(ary, enc_flag, self) break; case T_HASH: - /* RARRAY(dst)->ptr[RARRAY(dst)->len++] = hash2list(val, self); */ + /* rb_ary_push(dst, hash2list(val, self)); */ if (RTEST(enc_flag)) { val = hash2kv_enc(val, Qnil, self); } else { val = hash2kv(val, Qnil, self); } - size2 = RARRAY(val)->len; + size2 = RARRAY_LEN(val); for(idx2 = 0; idx2 < size2; idx2++) { - val2 = RARRAY(val)->ptr[idx2]; + val2 = RARRAY_PTR(val)[idx2]; switch(TYPE(val2)) { case T_ARRAY: str_val = ary2list(val2, enc_flag, self); - RARRAY(dst)->ptr[RARRAY(dst)->len++] = str_val; + rb_ary_push(dst, str_val); break; case T_HASH: @@ -324,13 +332,13 @@ ary2list(ary, enc_flag, self) } else { str_val = hash2list(val2, self); } - RARRAY(dst)->ptr[RARRAY(dst)->len++] = str_val; + rb_ary_push(dst, str_val); break; default: if (val2 != TK_None) { str_val = get_eval_string_core(val2, enc_flag, self); - RARRAY(dst)->ptr[RARRAY(dst)->len++] = str_val; + rb_ary_push(dst, str_val); } } @@ -352,7 +360,7 @@ ary2list(ary, enc_flag, self) default: if (val != TK_None) { str_val = get_eval_string_core(val, enc_flag, self); - RARRAY(dst)->ptr[RARRAY(dst)->len++] = str_val; + rb_ary_push(dst, str_val); if (req_chk_flag) { str_enc = rb_ivar_get(str_val, ID_at_enc); @@ -371,21 +379,21 @@ ary2list(ary, enc_flag, self) } if (RTEST(dst_enc) && !NIL_P(sys_enc)) { - for(idx = 0; idx < RARRAY(dst)->len; idx++) { - str_val = RARRAY(dst)->ptr[idx]; + for(idx = 0; idx < RARRAY_LEN(dst); idx++) { + str_val = RARRAY_PTR(dst)[idx]; if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) { str_val = rb_funcall(self, ID_toUTF8, 1, str_val); } else { str_val = rb_funcall(cTclTkLib, ID_toUTF8, 1, str_val); } - RARRAY(dst)->ptr[idx] = str_val; + RARRAY_PTR(dst)[idx] = str_val; } val = rb_apply(cTclTkLib, ID_merge_tklist, dst); if (TYPE(dst_enc) == T_STRING) { val = rb_funcall(cTclTkLib, ID_fromUTF8, 2, val, dst_enc); rb_ivar_set(val, ID_at_enc, dst_enc); } else { - rb_ivar_set(val, ID_at_enc, rb_str_new2("utf-8")); + rb_ivar_set(val, ID_at_enc, ENCODING_NAME_UTF8); } return val; } else { @@ -421,11 +429,10 @@ ary2list2(ary, enc_flag, self) req_chk_flag = 0; } - size = RARRAY(ary)->len; + size = RARRAY_LEN(ary); dst = rb_ary_new2(size); - RARRAY(dst)->len = 0; - for(idx = 0; idx < RARRAY(ary)->len; idx++) { - val = RARRAY(ary)->ptr[idx]; + for(idx = 0; idx < RARRAY_LEN(ary); idx++) { + val = RARRAY_PTR(ary)[idx]; str_val = Qnil; switch(TYPE(val)) { case T_ARRAY: @@ -447,7 +454,7 @@ ary2list2(ary, enc_flag, self) } if (!NIL_P(str_val)) { - RARRAY(dst)->ptr[RARRAY(dst)->len++] = str_val; + rb_ary_push(dst, str_val); if (req_chk_flag) { str_enc = rb_ivar_get(str_val, ID_at_enc); @@ -465,21 +472,21 @@ ary2list2(ary, enc_flag, self) } if (RTEST(dst_enc) && !NIL_P(sys_enc)) { - for(idx = 0; idx < RARRAY(dst)->len; idx++) { - str_val = RARRAY(dst)->ptr[idx]; + for(idx = 0; idx < RARRAY_LEN(dst); idx++) { + str_val = RARRAY_PTR(dst)[idx]; if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) { str_val = rb_funcall(self, ID_toUTF8, 1, str_val); } else { str_val = rb_funcall(cTclTkLib, ID_toUTF8, 1, str_val); } - RARRAY(dst)->ptr[idx] = str_val; + RARRAY_PTR(dst)[idx] = str_val; } val = rb_apply(cTclTkLib, ID_merge_tklist, dst); if (TYPE(dst_enc) == T_STRING) { val = rb_funcall(cTclTkLib, ID_fromUTF8, 2, val, dst_enc); rb_ivar_set(val, ID_at_enc, dst_enc); } else { - rb_ivar_set(val, ID_at_enc, rb_str_new2("utf-8")); + rb_ivar_set(val, ID_at_enc, ENCODING_NAME_UTF8); } return val; } else { @@ -503,38 +510,35 @@ assoc2kv(assoc, ary, self) int i, j, len; volatile VALUE pair; volatile VALUE val; - volatile VALUE dst = rb_ary_new2(2 * RARRAY(assoc)->len); + volatile VALUE dst = rb_ary_new2(2 * RARRAY_LEN(assoc)); - len = RARRAY(assoc)->len; + len = RARRAY_LEN(assoc); for(i = 0; i < len; i++) { - pair = RARRAY(assoc)->ptr[i]; + pair = RARRAY_PTR(assoc)[i]; if (TYPE(pair) != T_ARRAY) { - RARRAY(dst)->ptr[RARRAY(dst)->len++] = key2keyname(pair); + rb_ary_push(dst, key2keyname(pair)); continue; } - switch(RARRAY(assoc)->len) { + switch(RARRAY_LEN(assoc)) { case 2: - RARRAY(dst)->ptr[RARRAY(dst)->len++] = RARRAY(pair)->ptr[2]; + rb_ary_push(dst, RARRAY_PTR(pair)[2]); case 1: - RARRAY(dst)->ptr[RARRAY(dst)->len++] - = key2keyname(RARRAY(pair)->ptr[0]); + rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); case 0: continue; default: - RARRAY(dst)->ptr[RARRAY(dst)->len++] - = key2keyname(RARRAY(pair)->ptr[0]); + rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); - val = rb_ary_new2(RARRAY(pair)->len - 1); - RARRAY(val)->len = 0; - for(j = 1; j < RARRAY(pair)->len; j++) { - RARRAY(val)->ptr[RARRAY(val)->len++] = RARRAY(pair)->ptr[j]; + val = rb_ary_new2(RARRAY_LEN(pair) - 1); + for(j = 1; j < RARRAY_LEN(pair); j++) { + rb_ary_push(val, RARRAY_PTR(pair)[j]); } - RARRAY(dst)->ptr[RARRAY(dst)->len++] = val; + rb_ary_push(dst, val); } } @@ -554,40 +558,35 @@ assoc2kv_enc(assoc, ary, self) int i, j, len; volatile VALUE pair; volatile VALUE val; - volatile VALUE dst = rb_ary_new2(2 * RARRAY(assoc)->len); + volatile VALUE dst = rb_ary_new2(2 * RARRAY_LEN(assoc)); - len = RARRAY(assoc)->len; + len = RARRAY_LEN(assoc); for(i = 0; i < len; i++) { - pair = RARRAY(assoc)->ptr[i]; + pair = RARRAY_PTR(assoc)[i]; if (TYPE(pair) != T_ARRAY) { - RARRAY(dst)->ptr[RARRAY(dst)->len++] = key2keyname(pair); + rb_ary_push(dst, key2keyname(pair)); continue; } - switch(RARRAY(assoc)->len) { + switch(RARRAY_LEN(assoc)) { case 2: - RARRAY(dst)->ptr[RARRAY(dst)->len++] - = get_eval_string_core(RARRAY(pair)->ptr[2], Qtrue, self); + rb_ary_push(dst, get_eval_string_core(RARRAY_PTR(pair)[2], Qtrue, self)); case 1: - RARRAY(dst)->ptr[RARRAY(dst)->len++] - = key2keyname(RARRAY(pair)->ptr[0]); + rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); case 0: continue; default: - RARRAY(dst)->ptr[RARRAY(dst)->len++] - = key2keyname(RARRAY(pair)->ptr[0]); + rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0])); - val = rb_ary_new2(RARRAY(pair)->len - 1); - RARRAY(val)->len = 0; - for(j = 1; j < RARRAY(pair)->len; j++) { - RARRAY(val)->ptr[RARRAY(val)->len++] = RARRAY(pair)->ptr[j]; + val = rb_ary_new2(RARRAY_LEN(pair) - 1); + for(j = 1; j < RARRAY_LEN(pair); j++) { + rb_ary_push(val, RARRAY_PTR(pair)[j]); } - RARRAY(dst)->ptr[RARRAY(dst)->len++] - = get_eval_string_core(val, Qtrue, self); + rb_ary_push(dst, get_eval_string_core(val, Qtrue, self)); } } @@ -606,19 +605,18 @@ push_kv(key, val, args) { volatile VALUE ary; - ary = RARRAY(args)->ptr[0]; + ary = RARRAY_PTR(args)[0]; if (key == Qundef) return ST_CONTINUE; #if 0 rb_ary_push(ary, key2keyname(key)); if (val != TK_None) rb_ary_push(ary, val); #endif - RARRAY(ary)->ptr[RARRAY(ary)->len++] = key2keyname(key); + rb_ary_push(ary, key2keyname(key)); if (val == TK_None) return ST_CHECK; - RARRAY(ary)->ptr[RARRAY(ary)->len++] - = get_eval_string_core(val, Qnil, RARRAY(args)->ptr[1]); + rb_ary_push(ary, get_eval_string_core(val, Qnil, RARRAY_PTR(args)[1])); return ST_CHECK; } @@ -629,15 +627,10 @@ hash2kv(hash, ary, self) VALUE ary; VALUE self; { - volatile VALUE args = rb_ary_new2(2); - volatile VALUE dst = rb_ary_new2(2 * RHASH(hash)->tbl->num_entries); - - RARRAY(dst)->len = 0; + volatile VALUE dst = rb_ary_new2(2 * RHASH_SIZE(hash)); + volatile VALUE args = rb_ary_new3(2, dst, self); - RARRAY(args)->ptr[0] = dst; - RARRAY(args)->ptr[1] = self; - RARRAY(args)->len = 2; - st_foreach(RHASH(hash)->tbl, push_kv, args); + st_foreach(RHASH_TBL(hash), push_kv, args); if (NIL_P(ary)) { return dst; @@ -654,22 +647,21 @@ push_kv_enc(key, val, args) { volatile VALUE ary; - ary = RARRAY(args)->ptr[0]; + ary = RARRAY_PTR(args)[0]; if (key == Qundef) return ST_CONTINUE; #if 0 rb_ary_push(ary, key2keyname(key)); if (val != TK_None) { rb_ary_push(ary, get_eval_string_core(val, Qtrue, - RARRAY(args)->ptr[1])); + RARRAY_PTR(args)[1])); } #endif - RARRAY(ary)->ptr[RARRAY(ary)->len++] = key2keyname(key); + rb_ary_push(ary, key2keyname(key)); if (val == TK_None) return ST_CHECK; - RARRAY(ary)->ptr[RARRAY(ary)->len++] - = get_eval_string_core(val, Qtrue, RARRAY(args)->ptr[1]); + rb_ary_push(ary, get_eval_string_core(val, Qtrue, RARRAY_PTR(args)[1])); return ST_CHECK; } @@ -680,15 +672,10 @@ hash2kv_enc(hash, ary, self) VALUE ary; VALUE self; { - volatile VALUE args = rb_ary_new2(2); - volatile VALUE dst = rb_ary_new2(2 * RHASH(hash)->tbl->num_entries); + volatile VALUE dst = rb_ary_new2(2 * RHASH_SIZE(hash)); + volatile VALUE args = rb_ary_new3(2, dst, self); - RARRAY(dst)->len = 0; - - RARRAY(args)->ptr[0] = dst; - RARRAY(args)->ptr[1] = self; - RARRAY(args)->len = 2; - st_foreach(RHASH(hash)->tbl, push_kv_enc, args); + st_foreach(RHASH_TBL(hash), push_kv_enc, args); if (NIL_P(ary)) { return dst; @@ -804,7 +791,11 @@ get_eval_string_core(obj, enc_flag, self) return fromDefaultEnc_toUTF8(rb_str_new2(rb_id2name(SYM2ID(obj))), self); } } else { +#ifdef RUBY_VM + return rb_sym_to_s(obj); +#else return rb_str_new2(rb_id2name(SYM2ID(obj))); +#endif } case T_HASH: @@ -862,7 +853,7 @@ get_eval_string_core(obj, enc_flag, self) } rb_warning("fail to convert '%s' to string for Tk", - RSTRING(rb_funcall(obj, rb_intern("inspect"), 0, 0))->ptr); + RSTRING_PTR(rb_funcall(obj, rb_intern("inspect"), 0, 0))); return obj; } @@ -915,14 +906,13 @@ tk_conv_args(argc, argv, self) for(size = 0, idx = 2; idx < argc; idx++) { if (TYPE(argv[idx]) == T_HASH) { - size += 2 * RHASH(argv[idx])->tbl->num_entries; + size += 2 * RHASH_SIZE(argv[idx]); } else { size++; } } /* dst = rb_ary_new2(argc - 2); */ dst = rb_ary_new2(size); - RARRAY(dst)->len = 0; for(idx = 2; idx < argc; idx++) { if (TYPE(argv[idx]) == T_HASH) { if (RTEST(argv[1])) { @@ -931,8 +921,7 @@ tk_conv_args(argc, argv, self) hash2kv(argv[idx], dst, self); } } else if (argv[idx] != TK_None) { - RARRAY(dst)->ptr[RARRAY(dst)->len++] - = get_eval_string_core(argv[idx], argv[1], self); + rb_ary_push(dst, get_eval_string_core(argv[idx], argv[1], self)); } } @@ -966,13 +955,13 @@ tcl2rb_bool(self, value) value = rb_funcall(value, ID_downcase, 0); - if (RSTRING(value)->ptr == (char*)NULL) return Qnil; + if (RSTRING_PTR(value) == (char*)NULL) return Qnil; - if (RSTRING(value)->ptr[0] == '\0' - || strcmp(RSTRING(value)->ptr, "0") == 0 - || strcmp(RSTRING(value)->ptr, "no") == 0 - || strcmp(RSTRING(value)->ptr, "off") == 0 - || strcmp(RSTRING(value)->ptr, "false") == 0) { + if (RSTRING_PTR(value)[0] == '\0' + || strcmp(RSTRING_PTR(value), "0") == 0 + || strcmp(RSTRING_PTR(value), "no") == 0 + || strcmp(RSTRING_PTR(value), "off") == 0 + || strcmp(RSTRING_PTR(value), "false") == 0) { return Qfalse; } else { return Qtrue; @@ -983,21 +972,21 @@ static VALUE tkstr_to_dec(value) VALUE value; { - return rb_cstr_to_inum(RSTRING(value)->ptr, 10, 1); + return rb_cstr_to_inum(RSTRING_PTR(value), 10, 1); } static VALUE tkstr_to_int(value) VALUE value; { - return rb_cstr_to_inum(RSTRING(value)->ptr, 0, 1); + return rb_cstr_to_inum(RSTRING_PTR(value), 0, 1); } static VALUE tkstr_to_float(value) VALUE value; { - return rb_float_new(rb_cstr_to_dbl(RSTRING(value)->ptr, 1)); + return rb_float_new(rb_cstr_to_dbl(RSTRING_PTR(value), 1)); } static VALUE @@ -1005,7 +994,7 @@ tkstr_invalid_numstr(value) VALUE value; { rb_raise(rb_eArgError, - "invalid value for Number: '%s'", RSTRING(value)->ptr); + "invalid value for Number: '%s'", RSTRING_PTR(value)); return Qnil; /*dummy*/ } @@ -1024,7 +1013,7 @@ tkstr_to_number(value) { rb_check_type(value, T_STRING); - if (RSTRING(value)->ptr == (char*)NULL) return INT2FIX(0); + if (RSTRING_PTR(value) == (char*)NULL) return INT2FIX(0); return rb_rescue2(tkstr_to_int, value, tkstr_rescue_float, value, @@ -1046,8 +1035,8 @@ tkstr_to_str(value) char * ptr; int len; - ptr = RSTRING(value)->ptr; - len = RSTRING(value)->len; + ptr = RSTRING_PTR(value); + len = RSTRING_LEN(value); if (len > 1 && *ptr == '{' && *(ptr + len - 1) == '}') { return rb_str_new(ptr + 1, len - 2); @@ -1062,7 +1051,7 @@ tcl2rb_string(self, value) { rb_check_type(value, T_STRING); - if (RSTRING(value)->ptr == (char*)NULL) return rb_tainted_str_new2(""); + if (RSTRING_PTR(value) == (char*)NULL) return rb_tainted_str_new2(""); return tkstr_to_str(value); } @@ -1074,7 +1063,7 @@ tcl2rb_num_or_str(self, value) { rb_check_type(value, T_STRING); - if (RSTRING(value)->ptr == (char*)NULL) return rb_tainted_str_new2(""); + if (RSTRING_PTR(value) == (char*)NULL) return rb_tainted_str_new2(""); return rb_rescue2(tkstr_to_number, value, tkstr_to_str, value, @@ -1181,7 +1170,7 @@ each_attr_def(key, value, klass) switch(TYPE(key)) { case T_STRING: - key_id = rb_intern(RSTRING(key)->ptr); + key_id = rb_intern(RSTRING_PTR(key)); break; case T_SYMBOL: key_id = SYM2ID(key); @@ -1193,7 +1182,7 @@ each_attr_def(key, value, klass) switch(TYPE(value)) { case T_STRING: - value_id = rb_intern(RSTRING(value)->ptr); + value_id = rb_intern(RSTRING_PTR(value)); break; case T_SYMBOL: value_id = SYM2ID(value); @@ -1234,7 +1223,8 @@ cbsubst_get_subst_arg(argc, argv, self) VALUE self; { struct cbsubst_info *inf; - char *str, *buf, *ptr; + const char *str; + char *buf, *ptr; int i, j, len; ID id; volatile VALUE arg_sym, ret; @@ -1249,7 +1239,7 @@ cbsubst_get_subst_arg(argc, argv, self) for(i = 0; i < argc; i++) { switch(TYPE(argv[i])) { case T_STRING: - str = RSTRING(argv[i])->ptr; + str = RSTRING_PTR(argv[i]); arg_sym = ID2SYM(rb_intern(str)); break; case T_SYMBOL: @@ -1264,7 +1254,7 @@ cbsubst_get_subst_arg(argc, argv, self) str = rb_id2name(SYM2ID(ret)); } - id = rb_intern(RSTRING(rb_str_cat2(rb_str_new2("@"), str))->ptr); + id = rb_intern(RSTRING_PTR(rb_str_cat2(rb_str_new2("@"), str))); for(j = 0; j < len; j++) { if (inf->ivar[j] == id) break; @@ -1300,11 +1290,11 @@ cbsubst_get_subst_key(self, str) list = rb_funcall(cTclTkLib, ID_split_tklist, 1, str); - len = RARRAY(list)->len; + len = RARRAY_LEN(list); buf = ALLOC_N(char, len + 1); for(i = 0; i < len; i++) { - ptr = RSTRING(RARRAY(list)->ptr[i])->ptr; + ptr = RSTRING_PTR(RARRAY_PTR(list)[i]); if (*ptr == '%' && *(ptr + 2) == '\0') { *(buf + i) = *(ptr + 1); } else { @@ -1355,7 +1345,7 @@ cbsubst_table_setup(self, key_inf, proc_inf) { struct cbsubst_info *subst_inf; int idx; - int len = RARRAY(key_inf)->len; + int len = RARRAY_LEN(key_inf); int real_len = 0; char *key = ALLOC_N(char, len + 1); char *type = ALLOC_N(char, len + 1); @@ -1380,20 +1370,20 @@ cbsubst_table_setup(self, key_inf, proc_inf) * ivar ==> symbol */ for(idx = 0; idx < len; idx++) { - inf = RARRAY(key_inf)->ptr[idx]; + inf = RARRAY_PTR(key_inf)[idx]; if (TYPE(inf) != T_ARRAY) continue; - *(key + real_len) = (char)NUM2INT(RARRAY(inf)->ptr[0]); - *(type + real_len) = (char)NUM2INT(RARRAY(inf)->ptr[1]); + *(key + real_len) = NUM2CHR(RARRAY_PTR(inf)[0]); + *(type + real_len) = NUM2CHR(RARRAY_PTR(inf)[1]); *(ivar + real_len) = rb_intern( - RSTRING( + RSTRING_PTR( rb_str_cat2(rb_str_new2("@"), - rb_id2name(SYM2ID(RARRAY(inf)->ptr[2]))) - )->ptr + rb_id2name(SYM2ID(RARRAY_PTR(inf)[2]))) + ) ); - rb_attr(self, SYM2ID(RARRAY(inf)->ptr[2]), 1, 0, Qtrue); + rb_attr(self, SYM2ID(RARRAY_PTR(inf)[2]), 1, 0, Qtrue); real_len++; } *(key + real_len) = '\0'; @@ -1405,11 +1395,11 @@ cbsubst_table_setup(self, key_inf, proc_inf) * type ==> char code * proc ==> proc/method/obj (must respond to 'call') */ - len = RARRAY(proc_inf)->len; + len = RARRAY_LEN(proc_inf); for(idx = 0; idx < len; idx++) { - inf = RARRAY(proc_inf)->ptr[idx]; + inf = RARRAY_PTR(proc_inf)[idx]; if (TYPE(inf) != T_ARRAY) continue; - rb_hash_aset(proc, RARRAY(inf)->ptr[0], RARRAY(inf)->ptr[1]); + rb_hash_aset(proc, RARRAY_PTR(inf)[0], RARRAY_PTR(inf)[1]); } rb_const_set(self, ID_SUBST_INFO, @@ -1434,7 +1424,7 @@ cbsubst_scan_args(self, arg_key, val_ary) { struct cbsubst_info *inf; int idx; - int len = RARRAY(val_ary)->len; + int len = RARRAY_LEN(val_ary); char c; char *ptr; volatile VALUE dst = rb_ary_new2(len); @@ -1450,14 +1440,13 @@ cbsubst_scan_args(self, arg_key, val_ary) Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO), struct cbsubst_info, inf); - RARRAY(dst)->len = 0; for(idx = 0; idx < len; idx++) { - if (idx >= RSTRING(arg_key)->len) { + if (idx >= RSTRING_LEN(arg_key)) { proc = Qnil; - } else if (*(RSTRING(arg_key)->ptr + idx) == ' ') { + } else if (*(RSTRING_PTR(arg_key) + idx) == ' ') { proc = Qnil; } else { - ptr = strchr(inf->key, *(RSTRING(arg_key)->ptr + idx)); + ptr = strchr(inf->key, *(RSTRING_PTR(arg_key) + idx)); if (ptr == (char*)NULL) { proc = Qnil; } else { @@ -1467,10 +1456,9 @@ cbsubst_scan_args(self, arg_key, val_ary) } if (NIL_P(proc)) { - RARRAY(dst)->ptr[RARRAY(dst)->len++] = RARRAY(val_ary)->ptr[idx]; + rb_ary_push(dst, RARRAY_PTR(val_ary)[idx]); } else { - RARRAY(dst)->ptr[RARRAY(dst)->len++] - = rb_funcall(proc, ID_call, 1, RARRAY(val_ary)->ptr[idx]); + rb_ary_push(dst, rb_funcall(proc, ID_call, 1, RARRAY_PTR(val_ary)[idx])); } } @@ -1512,6 +1500,7 @@ tkobj_path(self) return rb_ivar_get(self, ID_at_path); } + /*************************************/ /* release date */ const char tkutil_release_date[] = TKUTIL_RELEASE_DATE; @@ -1635,5 +1624,9 @@ Init_tkutil() rb_define_method(mTK, "string", tcl2rb_string, 1); rb_define_method(mTK, "num_or_str", tcl2rb_num_or_str, 1); + /* --------------------- */ + rb_global_variable(&ENCODING_NAME_UTF8); + ENCODING_NAME_UTF8 = rb_obj_freeze(rb_str_new2("utf-8")); + /* --------------------- */ } -- cgit v1.2.3