diff --git a/ext/tcltklib/tcltklib.c b/ext/tcltklib/tcltklib.c index 990fbc38af..ba7fdc5000 100644 --- a/ext/tcltklib/tcltklib.c +++ b/ext/tcltklib/tcltklib.c @@ -48,20 +48,44 @@ int *tclDummyMathPtr = (int *) matherr; /*---- module TclTkLib ----*/ struct invoke_queue { + Tcl_Event ev; int argc; VALUE *argv; VALUE obj; int done; - VALUE result; + int safe_level; + VALUE *result; VALUE thread; - struct invoke_queue *next; }; -static struct invoke_queue *iqueue; static VALUE main_thread; +static VALUE eventloop_thread; +static VALUE watchdog_thread; +Tcl_Interp *current_interp; + +/* + * 'event_loop_max' is a maximum events which the eventloop processes in one + * term of thread scheduling. 'no_event_tick' is the count-up value when + * there are no event for processing. + * 'timer_tick' is a limit of one term of thread scheduling. + * If 'timer_tick' == 0, then not use the timer for thread scheduling. + */ +static int tick_counter; +#define DEFAULT_EVENT_LOOP_MAX 800 +#define DEFAULT_NO_EVENT_TICK 10 +#define DEFAULT_TIMER_TICK 0 +static int event_loop_max = DEFAULT_EVENT_LOOP_MAX; +static int no_event_tick = DEFAULT_NO_EVENT_TICK; +static int timer_tick = DEFAULT_TIMER_TICK; + +#if TCL_MAJOR_VERSION >= 8 +static int ip_ruby _((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST*)); +#else +static int ip_ruby _((ClientData, Tcl_Interp *, int, char **)); +#endif /* Tk_ThreadTimer */ -static Tcl_TimerToken timer_token; +static Tcl_TimerToken timer_token = (Tcl_TimerToken)NULL; /* timer callback */ static void _timer_for_tcl _((ClientData)); @@ -73,44 +97,230 @@ _timer_for_tcl(clientData) VALUE thread; Tk_DeleteTimerHandler(timer_token); - timer_token = Tk_CreateTimerHandler(100, _timer_for_tcl, (ClientData)0); - - CHECK_INTS; - q = iqueue; - while (q) { - tmp = q; - q = q->next; - if (!tmp->done) { - tmp->done = 1; - tmp->result = ip_invoke_real(tmp->argc, tmp->argv, tmp->obj); - thread = tmp->thread; - tmp = tmp->next; - rb_thread_run(thread); - } + if (timer_tick > 0) { + timer_token = Tk_CreateTimerHandler(timer_tick, _timer_for_tcl, + (ClientData)0); + } else { + timer_token = (Tcl_TimerToken)NULL; } - rb_thread_schedule(); + + /* rb_thread_schedule(); */ + timer_tick += event_loop_max; } -#if TCL_MAJOR_VERSION >= 8 -static int ip_ruby _((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST*)); -#else -static int ip_ruby _((ClientData, Tcl_Interp *, int, char **)); -#endif +static VALUE +set_eventloop_tick(self, tick) + VALUE self; + VALUE tick; +{ + int ttick = NUM2INT(tick); + + if (ttick < 0) { + rb_raise(rb_eArgError, "timer-tick parameter must be 0 or plus number"); + } + + /* delete old timer callback */ + Tk_DeleteTimerHandler(timer_token); + + timer_tick = ttick; + if (timer_tick > 0) { + /* start timer callback */ + timer_token = Tk_CreateTimerHandler(timer_tick, _timer_for_tcl, + (ClientData)0); + } else { + timer_token = (Tcl_TimerToken)NULL; + } + + return tick; +} + +static VALUE +get_eventloop_tick(self) + VALUE self; +{ + return INT2NUM(timer_tick); +} + +static VALUE +set_eventloop_weight(self, loop_max, no_event) + VALUE self; + VALUE loop_max; + VALUE no_event; +{ + int lpmax = NUM2INT(loop_max); + int no_ev = NUM2INT(no_event); + + if (lpmax <= 0 || no_ev <= 0) { + rb_raise(rb_eArgError, "weight parameters must be plus number"); + } + + event_loop_max = lpmax; + no_event_tick = no_ev; + + return rb_ary_new3(2, loop_max, no_event); +} + +static VALUE +get_eventloop_weight(self) + VALUE self; +{ + return rb_ary_new3(2, INT2NUM(event_loop_max), INT2NUM(no_event_tick)); +} + +VALUE +lib_mainloop_core(check_root_widget) + VALUE check_root_widget; +{ + VALUE current = eventloop_thread; + int check = (check_root_widget == Qtrue); + + Tk_DeleteTimerHandler(timer_token); + if (timer_tick > 0) { + timer_token = Tk_CreateTimerHandler(timer_tick, _timer_for_tcl, + (ClientData)0); + } else { + timer_token = (Tcl_TimerToken)NULL; + } + + for(;;) { + tick_counter = 0; + while(tick_counter < event_loop_max) { + if (Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT)) { + tick_counter++; + } else { + tick_counter += no_event_tick; + } + if (watchdog_thread != 0 && eventloop_thread != current) { + return Qnil; + } + } + if (check && Tk_GetNumMainWindows() == 0) { + break; + } + rb_thread_schedule(); + } + return Qnil; +} + + +VALUE +lib_mainloop_ensure(parent_evloop) + VALUE parent_evloop; +{ + if (ruby_debug) { + fprintf(stderr, "tcltklib: eventloop-thread : %lx -> %lx\n", + eventloop_thread, parent_evloop); + } + + Tk_DeleteTimerHandler(timer_token); + timer_token = (Tcl_TimerToken)NULL; + eventloop_thread = parent_evloop; + return Qnil; +} + +static VALUE +lib_mainloop_launcher(check_rootwidget) + VALUE check_rootwidget; +{ + VALUE parent_evloop = eventloop_thread; + + eventloop_thread = rb_thread_current(); + + if (ruby_debug) { + fprintf(stderr, "tcltklib: eventloop-thread : %lx -> %lx\n", + parent_evloop, eventloop_thread); + } + + return rb_ensure(lib_mainloop_core, check_rootwidget, + lib_mainloop_ensure, parent_evloop); +} /* execute Tk_MainLoop */ static VALUE -lib_mainloop(self) +lib_mainloop(argc, argv, self) + int argc; + VALUE *argv; VALUE self; { - timer_token = Tk_CreateTimerHandler(100, _timer_for_tcl, (ClientData)0); - DUMP1("start Tk_Mainloop"); - Tk_MainLoop(); - DUMP1("stop Tk_Mainloop"); - Tk_DeleteTimerHandler(timer_token); + VALUE check_rootwidget; + + if (rb_scan_args(argc, argv, "01", &check_rootwidget) == 0) { + check_rootwidget = Qtrue; + } else if (RTEST(check_rootwidget)) { + check_rootwidget = Qtrue; + } else { + check_rootwidget = Qfalse; + } + + return lib_mainloop_launcher(check_rootwidget); +} + +static VALUE +lib_mainloop_watchdog(argc, argv, self) + int argc; + VALUE *argv; + VALUE self; +{ + VALUE check_rootwidget; + VALUE evloop; + int check; + ID stop; + + if (rb_scan_args(argc, argv, "01", &check_rootwidget) == 0) { + check_rootwidget = Qtrue; + } else if (RTEST(check_rootwidget)) { + check_rootwidget = Qtrue; + } else { + check_rootwidget = Qfalse; + } + check = (check_rootwidget == Qtrue); + stop = rb_intern("stop?"); + + /* check other watchdog thread */ + if (watchdog_thread != 0) { + if (rb_funcall(watchdog_thread, stop, 0) == Qtrue) { + rb_funcall(watchdog_thread, rb_intern("kill"), 0); + } else { + return Qnil; + } + } + watchdog_thread = rb_thread_current(); + + /* watchdog start */ + do { + if (eventloop_thread == 0 + || rb_funcall(eventloop_thread, stop, 0) == Qtrue) { + /* start new eventloop thread */ + DUMP2("eventloop thread %lx is sleeping or dead", eventloop_thread); + evloop = rb_thread_create(lib_mainloop_launcher, + (void*)&check_rootwidget); + DUMP2("create new eventloop thread %lx", evloop); + rb_thread_run(evloop); + } + rb_thread_schedule(); + } while(!check || Tk_GetNumMainWindows() != 0); return Qnil; } +static VALUE +lib_do_one_event(argc, argv, self) + int argc; + VALUE *argv; + VALUE self; +{ + VALUE obj, vflags; + int flags; + + if (rb_scan_args(argc, argv, "01", &vflags) == 0) { + flags = 0; + } else { + Check_Type(vflags, T_FIXNUM); + flags = FIX2INT(vflags); + } + return INT2NUM(Tcl_DoOneEvent(flags)); +} + /*---- class TclTkIp ----*/ struct tcltkip { Tcl_Interp *ip; /* the interpreter */ @@ -245,6 +455,7 @@ ip_new(self) /* from Tk_Main() */ DUMP1("Tcl_CreateInterp"); ptr->ip = Tcl_CreateInterp(); + current_interp = ptr->ip; /* from Tcl_AppInit() */ DUMP1("Tcl_Init"); @@ -459,48 +670,103 @@ ip_invoke_real(argc, argv, obj) return rb_str_new2(ptr->ip->result); } +VALUE +ivq_safelevel_handler(arg, ivq) + VALUE arg; + VALUE ivq; +{ + struct invoke_queue *q; + + Data_Get_Struct(ivq, struct invoke_queue, q); + DUMP2("(safe-level handler) $SAFE = %d", q->safe_level); + rb_set_safe_level(q->safe_level); + return ip_invoke_real(q->argc, q->argv, q->obj); +} + +int +invoke_queue_handler(evPtr, flags) + Tcl_Event *evPtr; + int flags; +{ + struct invoke_queue *tmp, *q = (struct invoke_queue *)evPtr; + + DUMP1("do_invoke_queue_handler"); + DUMP2("invoke queue_thread : %lx", rb_thread_current()); + DUMP2("added by thread : %lx", q->thread); + + if (q->done) { + /* processed by another event-loop */ + return 0; + } + + /* process it */ + q->done = 1; + + /* check safe-level */ + if (rb_safe_level() != q->safe_level) { + *(q->result) = rb_funcall(rb_proc_new(ivq_safelevel_handler, + Data_Wrap_Struct(rb_cData,0,0,q)), + rb_intern("call"), 0); + } else { + *(q->result) = ip_invoke_real(q->argc, q->argv, q->obj); + } + + /* back to caller */ + rb_thread_run(q->thread); + + /* end of handler : remove it */ + return 1; +} + static VALUE ip_invoke(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { - struct invoke_queue *tmp, *p; - VALUE result = rb_thread_current(); + struct invoke_queue *tmp; + VALUE current = rb_thread_current(); + VALUE result; + VALUE *alloc_argv, *alloc_result; + Tcl_QueuePosition position; - if (result == main_thread) { - return ip_invoke_real(argc, argv, obj); + if (eventloop_thread == 0 || current == eventloop_thread) { + DUMP2("invoke from current eventloop %lx", current); + return ip_invoke_real(argc, argv, obj); } - tmp = ALLOC(struct invoke_queue); + + DUMP2("invoke from thread %lx (NOT current eventloop)", current); + + /* allocate memory (protected from Tcl_ServiceEvent) */ + alloc_argv = ALLOC_N(VALUE,argc); + MEMCPY(alloc_argv, argv, VALUE, argc); + alloc_result = ALLOC(VALUE); + + /* allocate memory (freed by Tcl_ServiceEvent */ + tmp = (struct invoke_queue *)Tcl_Alloc(sizeof(struct invoke_queue)); + + /* construct event data */ + tmp->done = 0; tmp->obj = obj; tmp->argc = argc; - tmp->argv = ALLOC_N(VALUE, argc); - MEMCPY(tmp->argv, argv, VALUE, argc); - tmp->thread = result; - tmp->done = 0; + tmp->argv = alloc_argv; + tmp->result = alloc_result; + tmp->thread = current; + tmp->safe_level = rb_safe_level(); + tmp->ev.proc = invoke_queue_handler; + position = TCL_QUEUE_TAIL; - tmp->next = iqueue; - iqueue = tmp; + /* add the handler to Tcl event queue */ + Tcl_QueueEvent(&tmp->ev, position); + /* wait for the handler to be processed */ rb_thread_stop(); - result = tmp->result; - if (iqueue == tmp) { - iqueue = tmp->next; - free(tmp->argv); - free(tmp); - return result; - } - p = iqueue; - while (p->next) { - if (p->next == tmp) { - p->next = tmp->next; - free(tmp->argv); - free(tmp); - break; - } - p = p->next; - } + /* get result & free allocated memory */ + result = *alloc_result; + free(alloc_argv); + free(alloc_result); + return result; } @@ -533,6 +799,14 @@ Init_tcltklib() VALUE lib = rb_define_module("TclTkLib"); VALUE ip = rb_define_class("TclTkIp", rb_cObject); + VALUE ev_flag = rb_define_module_under(lib, "EventFlag"); + rb_define_const(ev_flag, "WINDOW", INT2FIX(TCL_WINDOW_EVENTS)); + rb_define_const(ev_flag, "FILE", INT2FIX(TCL_FILE_EVENTS)); + rb_define_const(ev_flag, "TIMER", INT2FIX(TCL_TIMER_EVENTS)); + rb_define_const(ev_flag, "IDLE", INT2FIX(TCL_IDLE_EVENTS)); + rb_define_const(ev_flag, "ALL", INT2FIX(TCL_ALL_EVENTS)); + rb_define_const(ev_flag, "DONT_WAIT", INT2FIX(TCL_DONT_WAIT)); + #if defined USE_TCL_STUBS && defined USE_TK_STUBS extern int ruby_tcltk_stubs(); int ret = ruby_tcltk_stubs(); @@ -543,7 +817,16 @@ Init_tcltklib() eTkCallbackBreak = rb_define_class("TkCallbackBreak", rb_eStandardError); eTkCallbackContinue = rb_define_class("TkCallbackContinue",rb_eStandardError); - rb_define_module_function(lib, "mainloop", lib_mainloop, 0); + rb_define_module_function(lib, "mainloop", lib_mainloop, -1); + rb_define_module_function(lib, "mainloop_watchdog", + lib_mainloop_watchdog, -1); + rb_define_module_function(lib, "do_one_event", lib_do_one_event, -1); + 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_eventloop_weight", + set_eventloop_weight, 2); + rb_define_module_function(lib, "get_eventloop_weight", + get_eventloop_weight, 0); rb_define_singleton_method(ip, "new", ip_new, 0); rb_define_method(ip, "_eval", ip_eval, 1); @@ -551,10 +834,19 @@ Init_tcltklib() rb_define_method(ip, "_fromUTF8",ip_fromUTF8,2); rb_define_method(ip, "_invoke", ip_invoke, -1); rb_define_method(ip, "_return_value", ip_retval, 0); - rb_define_method(ip, "mainloop", lib_mainloop, 0); + rb_define_method(ip, "mainloop", lib_mainloop, -1); + rb_define_method(ip, "mainloop_watchdog", lib_mainloop_watchdog, -1); + rb_define_method(ip, "do_one_event", lib_do_one_event, -1); + rb_define_method(ip, "set_eventloop_tick", set_eventloop_tick, 1); + rb_define_method(ip, "get_eventloop_tick", get_eventloop_tick, 0); + rb_define_method(ip, "set_eventloop_weight", set_eventloop_weight, 2); + rb_define_method(ip, "get_eventloop_weight", get_eventloop_weight, 0); rb_define_method(ip, "restart", lib_restart, 0); main_thread = rb_thread_current(); + eventloop_thread = 0; + watchdog_thread = 0; + #ifdef __MACOS__ _macinit(); #endif diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb index bac2ae35f9..2e33c4294c 100644 --- a/ext/tk/lib/tk.rb +++ b/ext/tk/lib/tk.rb @@ -132,6 +132,13 @@ module TkComm end private :tk_tcl2ruby, :tk_split_list, :tk_split_simplelist + def _symbolkey2str(keys) + h = {} + keys.each{|key,value| h[key.to_s] = value} + h + end + private :_symbolkey2str + def hash_kv(keys) conf = [] if keys and keys != None @@ -204,6 +211,8 @@ module TkComm return nil if str == None if str.kind_of?(String) # do nothing + elsif str.kind_of?(Symbol) + str = str.id2name elsif str.kind_of?(Hash) str = hash_kv(str).join(" ") elsif str.kind_of?(Array) @@ -259,13 +268,15 @@ module TkComm end private :install_cmd, :uninstall_cmd - def install_win(ppath) - id = format("w%.4d", Tk_IDs[1]) - Tk_IDs[1] += 1 + def install_win(ppath,name=nil) + if !name or name == '' + name = format("w%.4d", Tk_IDs[1]) + Tk_IDs[1] += 1 + end if !ppath or ppath == "." - @path = format(".%s", id); + @path = format(".%s", name); else - @path = format("%s.%s", ppath, id) + @path = format("%s.%s", ppath, name) end Tk_WINDOWS[@path] = self end @@ -483,6 +494,8 @@ module TkCore } EOL + EventFlag = TclTkLib::EventFlag + def callback_break fail TkCallbackBreak, "Tk callback returns 'break' status" end @@ -616,12 +629,42 @@ module TkCore tk_call('info', *args) end - def mainloop - TclTkLib.mainloop + def mainloop(check_root = true) + TclTkLib.mainloop(check_root) end - def restart + def mainloop_watchdog(check_root = true) + TclTkLib.mainloop_watchdog(check_root) + end + + def do_one_event(flag = 0) + TclTkLib.do_one_event(flag) + end + + def set_eventloop_tick(timer_tick) + TclTkLib.set_eventloop_tick(timer_tick) + end + + def get_eventloop_tick() + TclTkLib.get_eventloop_tick + end + + def set_eventloop_weight(loop_max, no_event_tick) + TclTkLib.set_eventloop_weight(loop_max, no_event_tick) + end + + def get_eventloop_weight() + TclTkLib.get_eventloop_weight + end + + def restart(app_name = nil, use = nil) + tk_call('set', 'argv0', app_name) if app_name + if use + tk_call('set', 'argc', 2) + tk_call('set', 'argv', "-use #{use}") + end TkCore::INTERP.restart + TkComm::Tk_CMDTBL.clear TkComm::Tk_WINDOWS.clear nil end @@ -2077,12 +2120,87 @@ module TkOption tk_call 'option', 'clear' end def get win, name, klass - tk_call 'option', 'get', win ,name, klass + tk_call('option', 'get', win ,name, klass).taint end def readfile file, pri=None tk_call 'option', 'readfile', file, pri end module_function :add, :clear, :get, :readfile + + # support procs on the resource database + @@resource_proc_class = Class.new + class << @@resource_proc_class + private :new + + CARRIER = '.'.freeze + METHOD_TBL = {} + ADD_METHOD = false + SAFE_MODE = 4 + + def __check_proc_string__(str) + # If you want to check the proc_string, do it in this method. + str + end + + def method_missing(id, *args) + res_proc = self::METHOD_TBL[id] + unless res_proc.kind_of? Proc + if id == :new || (!self::METHOD_TBL.has_key?(id) && !self::ADD_METHOD) + raise NoMethodError, + "not support resource-proc '#{id.id2name}' for #{self.name}" + end + proc_str = TkOption.get(self::CARRIER, id.id2name, '') + proc_str = '{' + proc_str + '}' unless /\A\{.*\}\Z/ =~ proc_str + proc_str = __check_proc_string__(proc_str) + res_proc = eval 'Proc.new' + proc_str + self::METHOD_TBL[id] = res_proc + end + proc{ + $SAFE = self::SAFE_MODE + res_proc.call(*args) + }.call + end + + private :__check_proc_string__, :method_missing + end + + def new_proc_class(klass, func, safe = 4, add = false, parent = nil) + klass = klass.to_s if klass.kind_of? Symbol + unless (?A..?Z) === klass[0] + fail ArgumentError, "bad string '#{klass}' for class name" + end + unless func.kind_of? Array + fail ArgumentError, "method-list must be Array" + end + func_str = func.join(' ') + if parent == nil + install_win(parent) + elsif parent <= @@resource_proc_class + install_win(parent::CARRIER) + else + fail ArgumentError, "parent must be Resource-Proc class" + end + carrier = Tk.tk_call('frame', @path, '-class', klass) + + body = <<-"EOD" + class #{klass} < TkOption.module_eval('@@resource_proc_class') + CARRIER = '#{carrier}'.freeze + METHOD_TBL = {} + ADD_METHOD = #{add} + SAFE_MODE = #{safe} + %w(#{func_str}).each{|f| METHOD_TBL[f.intern] = nil } + end + EOD + + if parent.kind_of?(Class) && parent <= @@resource_proc_class + parent.class_eval body + eval parent.name + '::' + klass + else + eval body + eval 'TkOption::' + klass + end + end + module_function :new_proc_class end module TkTreatFont @@ -2096,6 +2214,7 @@ module TkTreatFont alias fontobj font_configinfo def font_configure(slot) + slot = _symbolkey2str(slot) if (fnt = slot.delete('font')) if fnt.kind_of? TkFont return fnt.call_font_configure(self.path, self.path,'configure',slot) @@ -2203,6 +2322,7 @@ module TkTreatItemFont def tagfont_configure(tagOrId, slot) pathname = __item_pathname(tagOrId) + slot = _symbolkey2str(slot) if (fnt = slot.delete('font')) if fnt.kind_of? TkFont return fnt.call_font_configure(pathname, self.path, @@ -2345,7 +2465,7 @@ class TkObjectparent} end - @classname = keys['class'] - @colormap = keys['colormap'] - @container = keys['container'] - @visual = keys['visual'] end - super(parent, keys) + if keys.key?('classname') + keys['class'] = keys.delete('classname') + end + @classname = keys['class'] + @colormap = keys['colormap'] + @container = keys['container'] + @visual = keys['visual'] + super(keys) end def create_self(keys) @@ -3170,7 +3325,7 @@ class TkListboxval}) else tk_call 'itemconfigure', index, "-#{key}", val @@ -3198,7 +3357,7 @@ class TkListboxval}) else tk_call 'entryconfigure', index, "-#{key}", val @@ -3333,7 +3496,7 @@ class TkMenu +# +# $Id$ # require 'tk' @@ -11,18 +12,16 @@ class TkAfter Tk_CBID = [0] Tk_CBTBL = {} - INTERP._invoke("proc", "rb_after", "args", "ruby [format \"TkAfter.callback %%Q!%s!\" $args]") + INTERP._invoke("proc", "rb_after", "id", "ruby [format \"TkAfter.callback %%Q!%s!\" $id]") ############################### # class methods ############################### - def TkAfter.callback(arg) + def TkAfter.callback(obj_id) @after_id = nil - arg = Array(tk_split_list(arg)) - obj_id = arg.shift ex_obj = Tk_CBTBL[obj_id] return nil if ex_obj == nil; # canceled - _get_eval_string(ex_obj.do_callback(*arg)) + _get_eval_string(ex_obj.do_callback) end def TkAfter.info @@ -35,10 +34,10 @@ class TkAfter ############################### # instance methods ############################### - def do_callback(*args) + def do_callback @in_callback = true begin - ret = @current_proc.call(*args) + @return_value = @current_proc.call(self) rescue StandardError, NameError if @cancel_on_exception cancel @@ -48,21 +47,22 @@ class TkAfter end end if @set_next - set_next_callback(*args) + set_next_callback(@current_args) else @set_next = true end @in_callback = false - ret + @return_value end def set_callback(sleep, args=nil) - @after_script = "rb_after #{@id} #{_get_eval_string(args)}" + @after_script = "rb_after #{@id}" @after_id = tk_call('after', sleep, @after_script) + @current_args = args @current_script = [sleep, @after_script] end - def set_next_callback(*args) + def set_next_callback(args) if @running == false || @proc_max == 0 || @do_loop == 0 Tk_CBTBL[@id] = nil ;# for GC @running = false @@ -81,7 +81,7 @@ class TkAfter @current_args = args if @sleep_time.kind_of? Proc - sleep = @sleep_time.call(*args) + sleep = @sleep_time.call(self) else sleep = @sleep_time end @@ -91,15 +91,7 @@ class TkAfter @current_pos += 1 @current_proc = cmd - if cmd_args[0].kind_of? Proc - #c = cmd_args.shift - #cb_args = c.call(*(cmd_args + args)) - cb_args = cmd_args[0].call(*args) - else - cb_args = cmd_args - end - - set_callback(sleep, cb_args) + set_callback(sleep, cmd_args) end def initialize(*args) @@ -115,6 +107,7 @@ class TkAfter @current_script = [] @current_proc = nil @current_args = nil + @return_value = nil @sleep_time = 0 @current_sleep = 0 @@ -137,7 +130,10 @@ class TkAfter attr :after_id attr :after_script attr :current_proc + attr :current_args attr :current_sleep + alias :current_interval :current_sleep + attr :return_value attr_accessor :loop_exec @@ -257,7 +253,7 @@ class TkAfter set_callback(sleep, @init_args) @set_next = false if @in_callback else - set_next_callback(*@init_args) + set_next_callback(@init_args) end self diff --git a/ext/tk/lib/tkcanvas.rb b/ext/tk/lib/tkcanvas.rb index 94376072d3..ac6ed5362f 100644 --- a/ext/tk/lib/tkcanvas.rb +++ b/ext/tk/lib/tkcanvas.rb @@ -1,4 +1,4 @@ - +# # tkcanvas.rb - Tk canvas classes # $Date$ # by Yukihiro Matsumoto @@ -180,7 +180,7 @@ class TkCanvasvalue}) else tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value @@ -226,7 +229,7 @@ class TkCanvas "(t1)&&(t2)" @@ -473,6 +476,7 @@ class TkcTag +# +# $Id$ require "tk" @@ -13,6 +15,7 @@ Radiobutton = TkRadioButton Checkbutton = TkCheckButton Message = TkMessage Entry = TkEntry +Spinbox = TkSpinbox Text = TkText Scale = TkScale Scrollbar = TkScrollbar @@ -28,10 +31,16 @@ Polygon = TkcPolygon Rectangle = TkcRectangle TextItem = TkcText WindowItem = TkcWindow +BitmapImage = TkBitmapImage +PhotoImage = TkPhotoImage Selection = TkSelection Winfo = TkWinfo Pack = TkPack +Grid = TkGrid +Place = TkPlace Variable = TkVariable +Font = TkFont +VirtualEvent = TkVirtualEvent def Mainloop Tk.mainloop diff --git a/ext/tk/lib/tkdialog.rb b/ext/tk/lib/tkdialog.rb index 1133db6ae9..8b8ee69128 100644 --- a/ext/tk/lib/tkdialog.rb +++ b/ext/tk/lib/tkdialog.rb @@ -23,6 +23,7 @@ class TkDialog < TkWindow @button_configs = proc{|num| button_configs num} if keys.kind_of? Hash + keys = _symbolkey2str(keys) @title = keys['title'] if keys['title'] @message = keys['message'] if keys['message'] @bitmap = keys['bitmap'] if keys['bitmap'] diff --git a/ext/tk/lib/tkentry.rb b/ext/tk/lib/tkentry.rb index f301bbdace..f2706125cb 100644 --- a/ext/tk/lib/tkentry.rb +++ b/ext/tk/lib/tkentry.rb @@ -73,6 +73,7 @@ class TkEntryval}) else tk_send 'tag', 'configure', tag, "-#{key}", val @@ -214,7 +217,7 @@ class TkText