From 4f7d0eaaf362cb6e43077637ab6db7da118679ab Mon Sep 17 00:00:00 2001 From: nagai Date: Tue, 25 Jan 2005 05:09:22 +0000 Subject: * ext/tcltklib/tcltklib.c: fix SEGV bug; trouble on canceling remained after scripts [ruby-dev:25479]: NULL current namespce when deleting Tk interpreter [ruby-talk:126225] * ext/tcltklib/extconf.rb: bug fix; TCL_ENABLE_THREAD flag is inverted [ruby-talk:126360] * ext/tcltklib/extconf.rb: add yet another native-thread check * ext/tk/tkutil.c: fix SEGV bug; NULL string pointer when finalize Ruby interpreter * ext/tk/lib/multi-tk.rb: avoid warning for deleted safeTk ip frame * ext/tk/lib/tk/bindtag.rb: bug fix; new method of named bindtag doesn't return the created object [ruby-dev:25479] * ext/tk/lib/tk/menu.rb: bug on treating arguments [ruby-dev:25479] * ext/tk/lib/tk.rb: bug fix; cannot accept a callback ID string for a command argument [ruby-dev:25479] * ext/tk/lib/multi-tk.rb: ditto * ext/tk/lib/tk/*.rb: ditto * ext/tk/lib/tkextlib/*.rb: ditto * ext/tk/sample/demos-jp/anilabel.rb: new demo script * ext/tk/sample/demos-en/anilabel.rb: ditto * ext/tk/sample/tkHTML/ss.rb: local variable scope bug fix [ruby-dev:25479] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@7821 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 37 ++++++ ext/tcltklib/extconf.rb | 13 +- ext/tcltklib/tcltklib.c | 172 +++++++++++++++++------- ext/tk/ChangeLog.tkextlib | 30 +++++ ext/tk/lib/multi-tk.rb | 18 ++- ext/tk/lib/remote-tk.rb | 4 + ext/tk/lib/tk.rb | 14 +- ext/tk/lib/tk/bindtag.rb | 1 + ext/tk/lib/tk/canvas.rb | 4 +- ext/tk/lib/tk/canvastag.rb | 4 +- ext/tk/lib/tk/menu.rb | 2 + ext/tk/lib/tk/text.rb | 4 +- ext/tk/lib/tk/texttag.rb | 4 +- ext/tk/lib/tkextlib/blt/component.rb | 4 +- ext/tk/lib/tkextlib/blt/tabset.rb | 8 +- ext/tk/lib/tkextlib/blt/treeview.rb | 8 +- ext/tk/lib/tkextlib/bwidget/labelentry.rb | 4 +- ext/tk/lib/tkextlib/bwidget/listbox.rb | 8 +- ext/tk/lib/tkextlib/bwidget/notebook.rb | 4 +- ext/tk/lib/tkextlib/bwidget/spinbox.rb | 4 +- ext/tk/lib/tkextlib/bwidget/tree.rb | 8 +- ext/tk/lib/tkextlib/itk/incr_tk.rb | 4 +- ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb | 4 +- ext/tk/lib/tkextlib/tkDND/tkdnd.rb | 4 +- ext/tk/lib/tkextlib/treectrl/tktreectrl.rb | 4 +- ext/tk/sample/demos-en/anilabel.rb | 172 ++++++++++++++++++++++++ ext/tk/sample/demos-en/widget | 7 +- ext/tk/sample/demos-jp/anilabel.rb | 174 +++++++++++++++++++++++++ ext/tk/sample/demos-jp/widget | 8 +- ext/tk/sample/tkextlib/tkHTML/ss.rb | 2 + ext/tk/tkutil.c | 10 +- 31 files changed, 639 insertions(+), 105 deletions(-) create mode 100644 ext/tk/sample/demos-en/anilabel.rb create mode 100644 ext/tk/sample/demos-jp/anilabel.rb diff --git a/ChangeLog b/ChangeLog index 229645d676..aaa9cf31cd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,40 @@ +Tue Jan 25 14:05:52 2005 Hidetoshi NAGAI + + * ext/tcltklib/tcltklib.c: fix SEGV bug; trouble on canceling remained + after scripts [ruby-dev:25479]: NULL current namespce when deleting + Tk interpreter [ruby-talk:126225] + + * ext/tcltklib/extconf.rb: bug fix; TCL_ENABLE_THREAD flag is inverted + [ruby-talk:126360] + + * ext/tcltklib/extconf.rb: add yet another native-thread check + + * ext/tk/tkutil.c: fix SEGV bug; NULL string pointer when finalize + Ruby interpreter + + * ext/tk/lib/multi-tk.rb: avoid warning for deleted safeTk ip frame + + * ext/tk/lib/tk/bindtag.rb: bug fix; new method of named bindtag + doesn't return the created object [ruby-dev:25479] + + * ext/tk/lib/tk/menu.rb: bug on treating arguments [ruby-dev:25479] + + * ext/tk/lib/tk.rb: bug fix; cannot accept a callback ID string for + a command argument [ruby-dev:25479] + + * ext/tk/lib/multi-tk.rb: ditto + + * ext/tk/lib/tk/*.rb: ditto + + * ext/tk/lib/tkextlib/*.rb: ditto + + * ext/tk/sample/demos-jp/anilabel.rb: new demo script + + * ext/tk/sample/demos-en/anilabel.rb: ditto + + * ext/tk/sample/tkHTML/ss.rb: local variable scope bug fix + [ruby-dev:25479] + Mon Jan 24 15:44:25 2005 Yukihiro Matsumoto * document updates - [ruby-core:04296], [ruby-core:04301], diff --git a/ext/tcltklib/extconf.rb b/ext/tcltklib/extconf.rb index 201768cb0d..00aa2ca620 100644 --- a/ext/tcltklib/extconf.rb +++ b/ext/tcltklib/extconf.rb @@ -166,6 +166,15 @@ def pthread_check() # tcl-thread is unknown if try_run(< +int main() { + Tcl_Interp *ip; + ip = Tcl_CreateInterp(); + exit((Tcl_Eval(ip, "set tcl_platform(threaded)") == TCL_OK)? 0: 1); +} +EOF + tcl_enable_thread = true + elsif try_run(< static Tcl_ThreadDataKey dataKey; int main() { exit((Tcl_GetThreadData(&dataKey, 1) == dataKey)? 1: 0); } EOF @@ -230,11 +239,11 @@ EOF ** ***************************************************************************** ') - $CPPFLAGS += ' -DWITH_TCL_ENABLE_THREAD=0' + $CPPFLAGS += ' -DWITH_TCL_ENABLE_THREAD=1' return false else # ruby -> disable && tcl -> disable - $CPPFLAGS += ' -DWITH_TCL_ENABLE_THREAD=1' + $CPPFLAGS += ' -DWITH_TCL_ENABLE_THREAD=0' return true end end diff --git a/ext/tcltklib/tcltklib.c b/ext/tcltklib/tcltklib.c index a52994dd00..c9a72ed4bd 100644 --- a/ext/tcltklib/tcltklib.c +++ b/ext/tcltklib/tcltklib.c @@ -4,7 +4,7 @@ * Oct. 24, 1997 Y. Matsumoto */ -#define TCLTKLIB_RELEASE_DATE "2004-12-27" +#define TCLTKLIB_RELEASE_DATE "2005-01-25" #include "ruby.h" #include "rubysig.h" @@ -74,8 +74,8 @@ const char tcltklib_release_date[] = TCLTKLIB_RELEASE_DATE; static char *finalize_hook_name = "INTERP_FINALIZE_HOOK"; /* to cancel remained after-scripts when deleting IP */ -#define REMAINED_AFTER_IDS_VAR "__ruby_tcltklib_remained_after_script_list__" -#define CANCEL_REMAINED_AFTER_IDS "foreach id $__ruby_tcltklib_remained_after_script_list__ {after cancel $id}" +#define CANCEL_AFTER_SCRIPTS "__ruby_tcltklib_cancel_after_scripts__" +#define DEF_CANCEL_AFTER_SCRIPTS_PROC "proc __ruby_tcltklib_cancel_after_scripts__ {} {foreach id [after info] {after cancel $id}}" /* for callback break & continue */ static VALUE eTkCallbackReturn; @@ -204,6 +204,14 @@ static int ip_ruby_eval _((ClientData, Tcl_Interp *, int, char **)); static int ip_ruby_cmd _((ClientData, Tcl_Interp *, int, char **)); #endif +static int ip_null_namespace _((Tcl_Interp *)); +#if TCL_MAJOR_VERSION >= 8 +#ifndef Tcl_GetCurrentNamespace +EXTERN Tcl_Namespace * Tcl_GetCurrentNamespace _((Tcl_Interp *)); +#endif +#endif + + /*---- class TclTkIp ----*/ struct tcltkip { Tcl_Interp *ip; /* the interpreter */ @@ -1881,7 +1889,7 @@ ip_InterpExitCommand(clientData, interp, argc, argv) char *argv[]; #endif { - if (!Tcl_InterpDeleted(interp)) { + if (!Tcl_InterpDeleted(interp) && !ip_null_namespace(interp)) { Tcl_Preserve(interp); Tcl_Eval(interp, "interp eval {} {destroy .}; interp delete {}"); Tcl_Release(interp); @@ -3261,10 +3269,13 @@ VALUE del_root(ip) if (!Tcl_InterpDeleted(ip)) { Tcl_Preserve(ip); - while((main_win = Tk_MainWindow(ip)) != (Tk_Window)NULL) { + + if ( (main_win = Tk_MainWindow(ip)) != (Tk_Window)NULL + && !(((Tk_FakeWin*)main_win)->flags & TK_ALREADY_DEAD) ) { DUMP1("wait main_win is destroyed"); Tk_DestroyWindow(main_win); } + Tcl_Release(ip); } return Qnil; @@ -3277,9 +3288,15 @@ delete_slaves(ip) { Tcl_Interp *slave; Tcl_Obj *slave_list, *elem; + Tcl_CmdInfo info; char *slave_name; int i, len; + if (Tcl_InterpDeleted(ip) || ip_null_namespace(ip)) { + DUMP2("call delete_slaves() for deleted ip(%lx)", ip); + return; + } + DUMP2("delete slaves of ip(%lx)", ip); Tcl_Preserve(ip); @@ -3316,14 +3333,18 @@ delete_slaves(ip) Tcl_Preserve(slave); - if (!Tcl_InterpDeleted(slave)) { - if (Tcl_Eval(slave, "after info") == TCL_OK - && Tcl_SetVar(slave, - REMAINED_AFTER_IDS_VAR, - Tcl_GetStringResult(slave), - TCL_GLOBAL_ONLY) != (char *)NULL) { - DUMP1("cancel after scripts"); - Tcl_Eval(slave, CANCEL_REMAINED_AFTER_IDS); + if (!Tcl_InterpDeleted(slave) && !ip_null_namespace(slave)) { + if (Tcl_Eval(slave, DEF_CANCEL_AFTER_SCRIPTS_PROC) == TCL_OK) { + if (Tcl_GetCommandInfo(slave, CANCEL_AFTER_SCRIPTS, &info)) { + DUMP2("call cancel after scripts proc '%s'", + CANCEL_AFTER_SCRIPTS); + Tcl_Eval(slave, CANCEL_AFTER_SCRIPTS); + } + } + + if (Tcl_GetCommandInfo(slave, finalize_hook_name, &info)) { + DUMP2("call finalize hook proc '%s'", finalize_hook_name); + Tcl_Eval(slave, finalize_hook_name); } } @@ -3332,12 +3353,16 @@ delete_slaves(ip) /* delete slave */ del_root(slave); - while(!Tcl_InterpDeleted(slave)) { + /* while(!rbtk_InterpDeleted(slave)) { */ + if (!Tcl_InterpDeleted(slave)) { DUMP1("wait ip is deleted"); Tcl_DeleteInterp(slave); } Tcl_Release(slave); + + /* delete slave_name command */ + Tcl_DeleteCommand(ip, slave_name); } Tcl_DecrRefCount(slave_list); @@ -3359,7 +3384,7 @@ ip_free(ptr) DUMP2("IP ref_count = %d", ptr->ref_count); - if (!Tcl_InterpDeleted(ptr->ip)) { + if (!Tcl_InterpDeleted(ptr->ip) && !ip_null_namespace(ptr->ip)) { DUMP2("IP(%lx) is not deleted", ptr->ip); /* Tcl_Preserve(ptr->ip); */ rbtk_preserve_ip(ptr); @@ -3368,13 +3393,12 @@ ip_free(ptr) Tcl_ResetResult(ptr->ip); - if (Tcl_Eval(ptr->ip, "after info") == TCL_OK - && Tcl_SetVar(ptr->ip, - REMAINED_AFTER_IDS_VAR, - Tcl_GetStringResult(ptr->ip), - TCL_GLOBAL_ONLY) != (char *)NULL) { - DUMP1("cancel after scripts"); - Tcl_Eval(ptr->ip, CANCEL_REMAINED_AFTER_IDS); + if (Tcl_Eval(ptr->ip, DEF_CANCEL_AFTER_SCRIPTS_PROC) == TCL_OK) { + if (Tcl_GetCommandInfo(ptr->ip, CANCEL_AFTER_SCRIPTS, &info)) { + DUMP2("call cancel after scripts proc '%s'", + CANCEL_AFTER_SCRIPTS); + Tcl_Eval(ptr->ip, CANCEL_AFTER_SCRIPTS); + } } if (Tcl_GetCommandInfo(ptr->ip, finalize_hook_name, &info)) { @@ -3382,10 +3406,11 @@ ip_free(ptr) Tcl_Eval(ptr->ip, finalize_hook_name); } - del_root(ptr->ip); + /* del_root(ptr->ip); */ DUMP1("delete interp"); - while(!Tcl_InterpDeleted(ptr->ip)) { + /* while(!rbtk_InterpDeleted(ptr->ip)) { */ + if (!Tcl_InterpDeleted(ptr->ip)) { DUMP1("wait ip is deleted"); Tcl_DeleteInterp(ptr->ip); } @@ -3843,24 +3868,34 @@ static VALUE ip_delete(self) VALUE self; { + Tcl_CmdInfo info; struct tcltkip *ptr = get_ip(self); /* Tcl_Preserve(ptr->ip); */ rbtk_preserve_ip(ptr); - if (Tcl_Eval(ptr->ip, "after info") == TCL_OK - && Tcl_SetVar(ptr->ip, - REMAINED_AFTER_IDS_VAR, - Tcl_GetStringResult(ptr->ip), - TCL_GLOBAL_ONLY) != (char *)NULL) { - DUMP1("cancel after scripts"); - Tcl_Eval(ptr->ip, CANCEL_REMAINED_AFTER_IDS); + DUMP1("delete slaves"); + delete_slaves(ptr->ip); + + DUMP1("finalize operation"); + if (Tcl_Eval(ptr->ip, DEF_CANCEL_AFTER_SCRIPTS_PROC) == TCL_OK) { + if (Tcl_GetCommandInfo(ptr->ip, CANCEL_AFTER_SCRIPTS, &info)) { + DUMP2("call cancel after scripts proc '%s'", + CANCEL_AFTER_SCRIPTS); + Tcl_Eval(ptr->ip, CANCEL_AFTER_SCRIPTS); + } + } + + if (Tcl_GetCommandInfo(ptr->ip, finalize_hook_name, &info)) { + DUMP2("call finalize hook proc '%s'", finalize_hook_name); + Tcl_Eval(ptr->ip, finalize_hook_name); } del_root(ptr->ip); DUMP1("delete interp"); - while(!Tcl_InterpDeleted(ptr->ip)) { + /* while(!rbtk_InterpDeleted(ptr->ip)) { */ + if (!Tcl_InterpDeleted(ptr->ip)) { DUMP1("wait ip is deleted"); Tcl_DeleteInterp(ptr->ip); } @@ -3872,6 +3907,30 @@ ip_delete(self) } /* is deleted? */ +static int +ip_null_namespace(interp) + Tcl_Interp *interp; +{ +#if TCL_MAJOR_VERSION < 8 + return 0; +#else /* support Namespace */ + return ( Tcl_GetCurrentNamespace(interp) == (Tcl_Namespace *)NULL ); +#endif +} + +static VALUE +ip_has_null_namespace_p(self) + VALUE self; +{ + struct tcltkip *ptr = get_ip(self); + + if (ip_null_namespace(ptr->ip)) { + return Qtrue; + } else { + return Qfalse; + } +} + static VALUE ip_is_deleted_p(self) VALUE self; @@ -3922,7 +3981,11 @@ ip_get_result_string_obj(interp) # if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0 s = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &len); - return(rb_tainted_str_new(s, len)); + if (s == (char*)NULL) { + return rb_tainted_str_new2(""); + } else { + return(rb_tainted_str_new(s, len)); + } # else /* TCL_VERSION >= 8.1 */ volatile VALUE strval; @@ -3937,12 +4000,20 @@ ip_get_result_string_obj(interp) if (Tcl_GetCharLength(retobj) != Tcl_UniCharLen(Tcl_GetUnicode(retobj))) { /* possibly binary string */ s = Tcl_GetByteArrayFromObj(retobj, &len); - strval = rb_tainted_str_new(s, len); + if (s == (char*)NULL) { + strval = rb_tainted_str_new2(""); + } else { + strval = rb_tainted_str_new(s, len); + } rb_ivar_set(strval, ID_at_enc, rb_str_new2("binary")); } else { /* possibly text string */ s = Tcl_GetStringFromObj(retobj, &len); - strval = rb_tainted_str_new(s, len); + if (s == (char*)NULL) { + strval = rb_tainted_str_new2(""); + } else { + strval = rb_tainted_str_new(s, len); + } } rb_thread_critical = thr_crit_bup; @@ -3982,7 +4053,7 @@ ip_eval_real(self, cmd_str, cmd_len) Tcl_IncrRefCount(cmd); /* ip is deleted? */ - if (Tcl_InterpDeleted(ptr->ip)) { + if (Tcl_InterpDeleted(ptr->ip) || ip_null_namespace(ptr->ip)) { DUMP1("ip is deleted"); Tcl_DecrRefCount(cmd); rb_thread_critical = thr_crit_bup; @@ -4023,7 +4094,7 @@ ip_eval_real(self, cmd_str, cmd_len) DUMP2("Tcl_Eval(%s)", cmd_str); /* ip is deleted? */ - if (Tcl_InterpDeleted(ptr->ip)) { + if (Tcl_InterpDeleted(ptr->ip) || ip_null_namespace(ptr->ip)) { DUMP1("ip is deleted"); ptr->return_value = TCL_OK; return rb_tainted_str_new2(""); @@ -4228,7 +4299,7 @@ lib_restart(self) rb_secure(4); /* ip is deleted? */ - if (Tcl_InterpDeleted(ptr->ip)) { + if (Tcl_InterpDeleted(ptr->ip) || ip_null_namespace(ptr->ip)) { DUMP1("ip is deleted"); rb_raise(rb_eRuntimeError, "interpreter is deleted"); } @@ -4717,7 +4788,7 @@ ip_invoke_core(interp, argc, argv) ptr = get_ip(interp); /* ip is deleted? */ - if (Tcl_InterpDeleted(ptr->ip)) { + if (Tcl_InterpDeleted(ptr->ip) || ip_null_namespace(ptr->ip)) { DUMP1("ip is deleted"); return rb_tainted_str_new2(""); } @@ -5199,7 +5270,7 @@ ip_get_variable(self, varname_arg, flag_arg) Tcl_IncrRefCount(nameobj); /* ip is deleted? */ - if (Tcl_InterpDeleted(ptr->ip)) { + if (Tcl_InterpDeleted(ptr->ip) || ip_null_namespace(ptr->ip)) { DUMP1("ip is deleted"); Tcl_DecrRefCount(nameobj); rb_thread_critical = thr_crit_bup; @@ -5263,7 +5334,7 @@ ip_get_variable(self, varname_arg, flag_arg) char *ret; /* ip is deleted? */ - if (Tcl_InterpDeleted(ptr->ip)) { + if (Tcl_InterpDeleted(ptr->ip) || ip_null_namespace(ptr->ip)) { DUMP1("ip is deleted"); return rb_tainted_str_new2(""); } else { @@ -5335,7 +5406,7 @@ ip_get_variable2(self, varname_arg, index_arg, flag_arg) Tcl_IncrRefCount(idxobj); /* ip is deleted? */ - if (Tcl_InterpDeleted(ptr->ip)) { + if (Tcl_InterpDeleted(ptr->ip) || ip_null_namespace(ptr->ip)) { DUMP1("ip is deleted"); Tcl_DecrRefCount(nameobj); Tcl_DecrRefCount(idxobj); @@ -5400,7 +5471,7 @@ ip_get_variable2(self, varname_arg, index_arg, flag_arg) char *ret; /* ip is deleted? */ - if (Tcl_InterpDeleted(ptr->ip)) { + if (Tcl_InterpDeleted(ptr->ip) || ip_null_namespace(ptr->ip)) { DUMP1("ip is deleted"); return rb_tainted_str_new2(""); } else { @@ -5447,7 +5518,7 @@ ip_set_variable(self, varname_arg, value_arg, flag_arg) varname = varname_arg; value = value_arg; flag = flag_arg; - + StringValue(varname); StringValue(value); @@ -5497,7 +5568,7 @@ ip_set_variable(self, varname_arg, value_arg, flag_arg) # endif /* ip is deleted? */ - if (Tcl_InterpDeleted(ptr->ip)) { + if (Tcl_InterpDeleted(ptr->ip) || ip_null_namespace(ptr->ip)) { DUMP1("ip is deleted"); Tcl_DecrRefCount(nameobj); Tcl_DecrRefCount(valobj); @@ -5564,7 +5635,7 @@ ip_set_variable(self, varname_arg, value_arg, flag_arg) CONST char *ret; /* ip is deleted? */ - if (Tcl_InterpDeleted(ptr->ip)) { + if (Tcl_InterpDeleted(ptr->ip) || ip_null_namespace(ptr->ip)) { DUMP1("ip is deleted"); return rb_tainted_str_new2(""); } else { @@ -5661,7 +5732,7 @@ ip_set_variable2(self, varname_arg, index_arg, value_arg, flag_arg) Tcl_IncrRefCount(valobj); /* ip is deleted? */ - if (Tcl_InterpDeleted(ptr->ip)) { + if (Tcl_InterpDeleted(ptr->ip) || ip_null_namespace(ptr->ip)) { DUMP1("ip is deleted"); Tcl_DecrRefCount(nameobj); Tcl_DecrRefCount(idxobj); @@ -5722,7 +5793,7 @@ ip_set_variable2(self, varname_arg, index_arg, value_arg, flag_arg) CONST char *ret; /* ip is deleted? */ - if (Tcl_InterpDeleted(ptr->ip)) { + if (Tcl_InterpDeleted(ptr->ip) || ip_null_namespace(ptr->ip)) { DUMP1("ip is deleted"); return rb_tainted_str_new2(""); } else { @@ -5766,7 +5837,7 @@ ip_unset_variable(self, varname_arg, flag_arg) StringValue(varname); /* ip is deleted? */ - if (Tcl_InterpDeleted(ptr->ip)) { + if (Tcl_InterpDeleted(ptr->ip) || ip_null_namespace(ptr->ip)) { DUMP1("ip is deleted"); return Qtrue; } @@ -5808,7 +5879,7 @@ ip_unset_variable2(self, varname_arg, index_arg, flag_arg) StringValue(index); /* ip is deleted? */ - if (Tcl_InterpDeleted(ptr->ip)) { + if (Tcl_InterpDeleted(ptr->ip) || ip_null_namespace(ptr->ip)) { DUMP1("ip is deleted"); return Qtrue; } @@ -6401,6 +6472,7 @@ Init_tcltklib() rb_define_method(ip, "allow_ruby_exit=", ip_allow_ruby_exit_set, 1); rb_define_method(ip, "delete", ip_delete, 0); rb_define_method(ip, "deleted?", ip_is_deleted_p, 0); + rb_define_method(ip, "null_namespace?", ip_has_null_namespace_p, 0); rb_define_method(ip, "_eval", ip_eval, 1); rb_define_method(ip, "_toUTF8", ip_toUTF8, -1); rb_define_method(ip, "_fromUTF8", ip_fromUTF8, -1); diff --git a/ext/tk/ChangeLog.tkextlib b/ext/tk/ChangeLog.tkextlib index 653c6ef7dd..0bfa0ba5f2 100644 --- a/ext/tk/ChangeLog.tkextlib +++ b/ext/tk/ChangeLog.tkextlib @@ -1,3 +1,33 @@ +2005-01-25 Hidetoshi NAGAI + + * ext/tk/lib/tkextlib/blt/component.rb: bug fix. cannot accept + a callback ID string for a command argument. [ruby-dev:25479] + + * ext/tk/lib/tkextlib/blt/tabset.rb: ditto + + * ext/tk/lib/tkextlib/blt/treeview.rb: ditto + + * ext/tk/lib/tkextlib/bwidget/labelentry.rb: ditto + + * ext/tk/lib/tkextlib/bwidget/listbox.rb: ditto + + * ext/tk/lib/tkextlib/bwidget/notebook.rb: ditto + + * ext/tk/lib/tkextlib/bwidget/spinbox.rb: ditto + + * ext/tk/lib/tkextlib/bwidget/tree.rb: ditto + + * ext/tk/lib/tkextlib/itk/incr_tk.rb: ditto + + * ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb: ditto + + * ext/tk/lib/tkextlib/tkDND/tkdnd.rb: ditto + + * ext/tk/lib/tkextlib/treectrl/tktreectrl.rb: ditto + + * ext/tk/sample/tkHTML/ss.rb: local variable scope bug fix + [ruby-dev:25479] + 2004-12-24 Hidetoshi NAGAI * add BLT extension support diff --git a/ext/tk/lib/multi-tk.rb b/ext/tk/lib/multi-tk.rb index d292b5089d..ef4868fdef 100644 --- a/ext/tk/lib/multi-tk.rb +++ b/ext/tk/lib/multi-tk.rb @@ -762,7 +762,11 @@ class MultiTkIp #slave_ip.delete slave_ip._eval_without_enc('exit') end - top.destroy if top.winfo_exist? + begin + top.destroy if top.winfo_exist? + rescue + # ignore + end } tag = TkBindTag.new.bind('Destroy', slave_delete_proc) @@ -1560,10 +1564,14 @@ class << MultiTkIp __getip.delete end - def deleteed? + def deleted? __getip.deleted? end + def null_namespace? + __getip.null_namespace? + end + def abort(msg = nil) __getip.abort(msg) end @@ -1886,6 +1894,10 @@ class MultiTkIp @interp.deleted? end + def null_namespace? + @interp.null_namespace? + end + def abort(msg = nil) if master? if msg @@ -2217,7 +2229,7 @@ class MultiTkIp def set_bgerror_handler(cmd = Proc.new, slave = nil, &b) unless TkComm._callback_entry?(cmd) - unless slave + if !slave && b slave = cmd cmd = Proc.new(&b) end diff --git a/ext/tk/lib/remote-tk.rb b/ext/tk/lib/remote-tk.rb index 1ef5310bde..a2f8a46d4e 100644 --- a/ext/tk/lib/remote-tk.rb +++ b/ext/tk/lib/remote-tk.rb @@ -282,6 +282,10 @@ class RemoteTkIp end end + def null_namespace? + false + end + def restart fail RuntimeError, 'cannot restart the remote interpreter' end diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb index 9dae5f0899..7f734a0820 100644 --- a/ext/tk/lib/tk.rb +++ b/ext/tk/lib/tk.rb @@ -913,7 +913,7 @@ module TkComm #end def bind(tagOrClass, context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) - if TkComm._callback_entry?(args[0]) + if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new @@ -928,7 +928,7 @@ module TkComm #end def bind_append(tagOrClass, context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) - if TkComm._callback_entry?(args[0]) + if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new @@ -952,7 +952,7 @@ module TkComm #end def bind_all(context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) - if TkComm._callback_entry?(args[0]) + if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new @@ -967,7 +967,7 @@ module TkComm #end def bind_append_all(context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) - if TkComm._callback_entry?(args[0]) + if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new @@ -2131,7 +2131,7 @@ module TkBindCore #end def bind(context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) - if TkComm._callback_entry?(args[0]) + if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new @@ -2144,7 +2144,7 @@ module TkBindCore #end def bind_append(context, *args) # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) - if TkComm._callback_entry?(args[0]) + if TkComm._callback_entry?(args[0]) || !block_given? cmd = args.shift else cmd = Proc.new @@ -3940,7 +3940,7 @@ end #Tk.freeze module Tk - RELEASE_DATE = '2004-12-27'.freeze + RELEASE_DATE = '2005-01-25'.freeze autoload :AUTO_PATH, 'tk/variable' autoload :TCL_PACKAGE_PATH, 'tk/variable' diff --git a/ext/tk/lib/tk/bindtag.rb b/ext/tk/lib/tk/bindtag.rb index 737223e3df..9023a08e06 100644 --- a/ext/tk/lib/tk/bindtag.rb +++ b/ext/tk/lib/tk/bindtag.rb @@ -23,6 +23,7 @@ class TkBindTag @id = name BTagID_TBL[@id] = self bind(*args, &b) if args != [] + self } end diff --git a/ext/tk/lib/tk/canvas.rb b/ext/tk/lib/tk/canvas.rb index a0543cc42d..e9a2caccd6 100644 --- a/ext/tk/lib/tk/canvas.rb +++ b/ext/tk/lib/tk/canvas.rb @@ -100,7 +100,7 @@ class TkCanvas'top') + +# frame +TkFrame.new($anilabel_demo) {|frame| + TkButton.new(frame) { + text 'Dismiss' + command proc{ + tmppath = $anilabel_demo + $anilabel_demo = nil + tmppath.destroy + } + }.pack('side'=>'left', 'expand'=>'yes') + + TkButton.new(frame) { + text 'See Code' + command proc{showCode 'label'} + }.pack('side'=>'left', 'expand'=>'yes') + +}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') + +# create frame for label demo +f_left = TkLabelFrame.new($anilabel_demo, :text=>'Scrolling Texts') +f_right = TkLabelFrame.new($anilabel_demo, :text=>'GIF Image') +Tk.pack(f_left, f_right, 'side'=>'left', 'expand'=>'yes', 'fill'=>'both', + 'padx'=>10, 'pady'=>10) + +# animated label +class AnimatedTextLabel < TkLabel + def initialize(*args) + super(*args) + @timer = TkTimer.new{ _animation_callback } + @timer.loop_exec = -1 + # bind('Destroy'){ @timer.stop } + @btag = TkBindTag.new('Destroy'){ @timer.stop } + self.bindtags_unshift(@btag) + end + + def _animation_callback() + txt = self.text + self.text = (txt[1..-1] << txt[0]) + end + private :_animation_callback + + def start(interval) + @timer.set_interval(interval) + @timer.start + end + + def stop + @timer.stop + end +end + +# animated image +class AnimatedImageLabel < AnimatedTextLabel + def initialize(*args) + super(*args) + @destroy_image = false + @btag.bind_append('Destroy'){ + if @destroy_image + begin + self.image.delete + rescue + end + end + } + end + attr_accessor :destroy_image + + def _animation_callback() + img = self.image + + fmt = img.format + if fmt.kind_of?(Array) + if fmt[1].kind_of?(Hash) + # fmt == ['GIF', {'index'=>idx}] + idx = fmt[1]['index'] + else + # fmt == ['GIF', '-index', idx] :: Ruby1.8.2 returns this. + idx = fmt[2] + end + elsif fmt.kind_of?(String) && fmt =~ /GIF -index (\d+)/ + idx = $1.to_i + else + idx = -1 + end + + begin + img.format("GIF -index #{idx + 1}") + rescue => e + img.format("GIF -index 0") + end + end + private :_animation_callback +end + +# create labels +l1 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:ridge, + :font=>{:family=>'Courier', :size=>10}) +l2 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:groove, + :font=>{:family=>'Courier', :size=>10}) +l3 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:flat, + :font=>{:family=>'Courier', :size=>10}, :width=>18) +Tk.pack(l1, l2, l3, + :side=>:top, :expand=>true, :anchor=>:w, :padx=>10, :pady=>10) + +limg = AnimatedImageLabel.new(f_right, :borderwidth=>0) +limg.pack(:side=>:top, :expand=>true, :padx=>10, :pady=>10) + +# base64-encoded animated GIF file +tclPowerdData = <'GIF', :data=>tclPowerdData)).start(100) diff --git a/ext/tk/sample/demos-en/widget b/ext/tk/sample/demos-en/widget index 9df91c467b..1a4fb0b96d 100644 --- a/ext/tk/sample/demos-en/widget +++ b/ext/tk/sample/demos-en/widget @@ -388,6 +388,11 @@ txt.insert('end', " \n ", tag_demospace) txt.insert('end', "3. Color picker.\n", tag_demo, "demo-clrpick") txt.insert('end', " \n ", tag_demospace) +txt.insert('end', "\n") +txt.insert('end', "Animation\n", tag_title) +txt.insert('end', " \n ", tag_demospace) +txt.insert('end', "1. Animated labels (if supported)\n", tag_demo, "demo-anilabel") + txt.insert('end', "\n") txt.insert('end', "Miscellaneous\n", tag_title) txt.insert('end', " \n ", tag_demospace) @@ -780,7 +785,7 @@ end # def aboutBox Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo', - 'message'=>"Ruby/Tk widget demonstration Ver.1.4.4-en\n\n" + + 'message'=>"Ruby/Tk widget demonstration Ver.1.5.0-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 new file mode 100644 index 0000000000..8cbec50167 --- /dev/null +++ b/ext/tk/sample/demos-jp/anilabel.rb @@ -0,0 +1,174 @@ +# +# animated label widget demo (called by 'widget') +# +# based on Tcl/Tk8.5a2 widget demos + +# toplevel widget が存在すれば削除する +if defined?($anilabel_demo) && $anilabel_demo + $anilabel_demo.destroy + $anilabel_demo = nil +end + +# demo 用の toplevel widget を生成 +$anilabel_demo = TkToplevel.new {|w| + title("Animated Label Demonstration") + iconname("anilabel") + positionWindow(w) +} + +# label 生成 +msg = TkLabel.new($anilabel_demo) { + font $font + wraplength '4i' + justify 'left' + text "下には4つのアニメーションラベルが表示されています。左側にあるラベルは、内部のテキストメッセージをスクロールしたように見せることで動きを付けています。右側のラベルは、表示するイメージを変化させることで動きを与えています。" +} +msg.pack('side'=>'top') + +# frame 生成 +TkFrame.new($anilabel_demo) {|frame| + TkButton.new(frame) { + #text '了解' + text '閉じる' + command proc{ + tmppath = $anilabel_demo + $anilabel_demo = nil + tmppath.destroy + } + }.pack('side'=>'left', 'expand'=>'yes') + + TkButton.new(frame) { + text 'コード参照' + command proc{showCode 'label'} + }.pack('side'=>'left', 'expand'=>'yes') + +}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m') + +# label demo 用フレーム生成 +f_left = TkLabelFrame.new($anilabel_demo, :text=>'Scrolling Texts') +f_right = TkLabelFrame.new($anilabel_demo, :text=>'GIF Image') +Tk.pack(f_left, f_right, 'side'=>'left', 'expand'=>'yes', 'fill'=>'both', + 'padx'=>10, 'pady'=>10) + +# animated label +class AnimatedTextLabel < TkLabel + def initialize(*args) + super(*args) + @timer = TkTimer.new{ _animation_callback } + @timer.loop_exec = -1 + # bind('Destroy'){ @timer.stop } + @btag = TkBindTag.new('Destroy'){ @timer.stop } + self.bindtags_unshift(@btag) + end + + def _animation_callback() + txt = self.text + self.text = (txt[1..-1] << txt[0]) + end + private :_animation_callback + + def start(interval) + @timer.set_interval(interval) + @timer.start + end + + def stop + @timer.stop + end +end + +# animated image +class AnimatedImageLabel < AnimatedTextLabel + def initialize(*args) + super(*args) + @destroy_image = false + @btag.bind_append('Destroy'){ + if @destroy_image + begin + self.image.delete + rescue + end + end + } + end + attr_accessor :destroy_image + + def _animation_callback() + img = self.image + + fmt = img.format + if fmt.kind_of?(Array) + if fmt[1].kind_of?(Hash) + # fmt == ['GIF', {'index'=>idx}] + idx = fmt[1]['index'] + else + # fmt == ['GIF', '-index', idx] :: Ruby1.8.2 returns this. + idx = fmt[2] + end + elsif fmt.kind_of?(String) && fmt =~ /GIF -index (\d+)/ + idx = $1.to_i + else + idx = -1 + end + + begin + img.format("GIF -index #{idx + 1}") + rescue => e + img.format("GIF -index 0") + end + end + private :_animation_callback +end + +# label 生成 +l1 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:ridge, + :font=>{:family=>'Courier', :size=>10}) +l2 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:groove, + :font=>{:family=>'Courier', :size=>10}) +l3 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:flat, + :font=>{:family=>'Courier', :size=>10}, :width=>18) +Tk.pack(l1, l2, l3, + :side=>:top, :expand=>true, :anchor=>:w, :padx=>10, :pady=>10) + +limg = AnimatedImageLabel.new(f_right, :borderwidth=>0) +limg.pack(:side=>:top, :expand=>true, :padx=>10, :pady=>10) + +# base64-encoded animated GIF file +tclPowerdData = <'GIF', :data=>tclPowerdData)).start(100) diff --git a/ext/tk/sample/demos-jp/widget b/ext/tk/sample/demos-jp/widget index 6eaaece4c4..3be05c167c 100644 --- a/ext/tk/sample/demos-jp/widget +++ b/ext/tk/sample/demos-jp/widget @@ -437,6 +437,12 @@ txt.insert('end', " \n ", tag_demospace) txt.insert('end', "3. 色選択ダイアログ\n", tag_demo, "demo-clrpick") txt.insert('end', " \n ", tag_demospace) +txt.insert('end', "\n") +#txt.insert('end', "アニメーション\n", tag_middle) +txt.insert('end', "アニメーション\n", tag_kanji_title) +txt.insert('end', " \n ", tag_demospace) +txt.insert('end', "1. アニメーションラベル (機能に対応したバージョンのTkが必要)\n", tag_demo, "demo-anilabel") + txt.insert('end', "\n") #txt.insert('end', "その他\n", tag_middle) txt.insert('end', "その他\n", tag_kanji_title) @@ -807,7 +813,7 @@ end # def aboutBox Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo', - 'message'=>"Ruby/Tk ウィジェットデモ Ver.1.4.4-jp\n\n" + + 'message'=>"Ruby/Tk ウィジェットデモ Ver.1.5.0-jp\n\n" + "based on demos of Tk8.1 -- 8.5 " + "( Copyright:: " + "(c) 1996-1997 Sun Microsystems, Inc. / " + diff --git a/ext/tk/sample/tkextlib/tkHTML/ss.rb b/ext/tk/sample/tkextlib/tkHTML/ss.rb index 179bdc13cd..3dbb7ec716 100644 --- a/ext/tk/sample/tkextlib/tkHTML/ss.rb +++ b/ext/tk/sample/tkextlib/tkHTML/ss.rb @@ -159,6 +159,8 @@ href_binding = proc{|w, x, y| # # last_dir = Dir.pwd +load_file = nil + sel_load = proc{ filetypes = [ ['Html Files', ['.html', '.htm']], diff --git a/ext/tk/tkutil.c b/ext/tk/tkutil.c index e36f92af04..d88f7b9a72 100644 --- a/ext/tk/tkutil.c +++ b/ext/tk/tkutil.c @@ -8,7 +8,7 @@ ************************************************/ -#define TKUTIL_RELEASE_DATE "2004-12-23" +#define TKUTIL_RELEASE_DATE "2005-01-25" #include "ruby.h" #include "rubysig.h" @@ -824,6 +824,8 @@ tcl2rb_bool(self, value) value = rb_funcall(value, ID_downcase, 0); + if (RSTRING(value)->ptr == (char*)NULL) return Qnil; + if (RSTRING(value)->ptr[0] == '\0' || strcmp(RSTRING(value)->ptr, "0") == 0 || strcmp(RSTRING(value)->ptr, "no") == 0 @@ -880,6 +882,8 @@ tkstr_to_number(value) { rb_check_type(value, T_STRING); + if (RSTRING(value)->ptr == (char*)NULL) return INT2FIX(0); + return rb_rescue2(tkstr_to_int, value, tkstr_rescue_float, value, rb_eArgError, 0); @@ -916,6 +920,8 @@ tcl2rb_string(self, value) { rb_check_type(value, T_STRING); + if (RSTRING(value)->ptr == (char*)NULL) return rb_tainted_str_new2(""); + return tkstr_to_str(value); } @@ -926,6 +932,8 @@ tcl2rb_num_or_str(self, value) { rb_check_type(value, T_STRING); + if (RSTRING(value)->ptr == (char*)NULL) return rb_tainted_str_new2(""); + return rb_rescue2(tkstr_to_number, value, tkstr_to_str, value, rb_eArgError, 0); -- cgit v1.2.3