class MultiTkIp
methods for construction
get target IP
get info
instance methods to treat tables
class methods to treat tables
for callback operation
pseudo-toplevel operation support
Constants
- BASE_DIR
- RUN_EVENTLOOP_ON_MAIN_THREAD
Ruby 1.9 !!!!!!!!!!!!!!!!!!!!!!!!!!
- WITH_ENCODING
- WITH_RUBY_VM
Attributes
cmd[R]
ip[R]
ret[RW]
target[RW]
Public Class Methods
_DEFAULT_MASTER()
click to toggle source
# File lib/remote-tk.rb, line 21 def self._DEFAULT_MASTER # work only once if @flag @flag = nil @@DEFAULT_MASTER else nil end end
_IP_TABLE()
click to toggle source
# File lib/remote-tk.rb, line 17 def self._IP_TABLE; @@IP_TABLE; end
_TK_TABLE_LIST()
click to toggle source
# File lib/remote-tk.rb, line 18 def self._TK_TABLE_LIST; @@TK_TABLE_LIST; end
__getip()
click to toggle source
# File lib/multi-tk.rb, line 1459 def self.__getip current = Thread.current if current.kind_of?(@@CALLBACK_SUBTHREAD) return current[:callback_ip] end if TclTkLib.mainloop_thread? != false && current[:callback_ip] return current[:callback_ip] end if current.group == ThreadGroup::Default @@DEFAULT_MASTER else ip = @@IP_TABLE[current.group] unless ip fail SecurityError, "cannot call Tk methods on #{Thread.current.inspect}" end ip end end
__init_ip_env__(table, script)
click to toggle source
# File lib/multi-tk.rb, line 943 def self.__init_ip_env__(table, script) ret = [] 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 ret[0] end end
__pseudo_toplevel()
click to toggle source
# File lib/multi-tk.rb, line 833 def self.__pseudo_toplevel Thread.current.group == ThreadGroup::Default && MultiTkIp.__getip == @@DEFAULT_MASTER && self.__pseudo_toplevel_evaluable? && @pseudo_toplevel[1] end
__pseudo_toplevel=(m)
click to toggle source
# File lib/multi-tk.rb, line 839 def self.__pseudo_toplevel=(m) unless (Thread.current.group == ThreadGroup::Default && MultiTkIp.__getip == @@DEFAULT_MASTER) fail SecurityError, "no permission to manipulate" end # if m.kind_of?(Module) && m.respond_to?(:pseudo_toplevel_evaluable?) if m.respond_to?(:pseudo_toplevel_evaluable?) @pseudo_toplevel[0] = true @pseudo_toplevel[1] = m else fail ArgumentError, 'fail to set pseudo-toplevel' end self end
__pseudo_toplevel_evaluable=(mode)
click to toggle source
# File lib/multi-tk.rb, line 863 def self.__pseudo_toplevel_evaluable=(mode) unless (Thread.current.group == ThreadGroup::Default && MultiTkIp.__getip == @@DEFAULT_MASTER) fail SecurityError, "no permission to manipulate" end @pseudo_toplevel[0] = (mode)? true: false end
__pseudo_toplevel_evaluable?()
click to toggle source
# File lib/multi-tk.rb, line 855 def self.__pseudo_toplevel_evaluable? begin @pseudo_toplevel[0] && @pseudo_toplevel[1].pseudo_toplevel_evaluable? rescue Exception false end end
_ip_id_()
click to toggle source
# File lib/multi-tk.rb, line 1451 def self._ip_id_ __getip._ip_id_ end
add_tk_procs(name, args=nil, body=nil)
click to toggle source
# File lib/multi-tk.rb, line 1800 def self.add_tk_procs(name, args=nil, body=nil) if name.kind_of?(Array) # => an array of [name, args, body] name.each{|param| self.add_tk_procs(*param)} else name = name.to_s @@ADD_TK_PROCS << [name, args, body] @@IP_TABLE.each{|tg, ip| ip._add_tk_procs(name, args, body) } end end
alive?()
click to toggle source
# File lib/multi-tk.rb, line 1612 def self.alive? __getip.alive? end
assign_receiver_and_watchdog(target)
click to toggle source
# File lib/multi-tk.rb, line 911 def self.assign_receiver_and_watchdog(target) ret = [nil] @assign_thread.raise(@assign_request.new(target, ret)) while ret[0] == nil unless @assign_thread.alive? raise RuntimeError, 'lost the thread to assign a receiver and a watchdog thread' end end if ret[0].kind_of?(Exception) raise ret[0] else ret[0] end end
cb_entry_class()
click to toggle source
# File lib/multi-tk.rb, line 1831 def self.cb_entry_class @@CB_ENTRY_CLASS end
create_table()
click to toggle source
# File lib/multi-tk.rb, line 1742 def self.create_table if __getip.slave? begin raise SecurityError, "slave-IP has no permission creating a new table" rescue SecurityError => e #p e.backtrace # Is called on a Ruby/Tk library? caller_info = e.backtrace[1] if caller_info =~ %r{^#{MultiTkIp::BASE_DIR}/(tk|tkextlib)/[^:]+\.rb:} # Probably, caller is a Ruby/Tk library --> allow creating else raise e end end end id = @@TK_TABLE_LIST.size obj = Object.new @@TK_TABLE_LIST << obj 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) end } obj.freeze @@IP_TABLE.each{|tg, ip| ip._add_new_tables } return obj end
get_cb_entry(cmd)
click to toggle source
# File lib/multi-tk.rb, line 1834 def self.get_cb_entry(cmd) @@CB_ENTRY_CLASS.new(__getip, cmd).freeze end
inherited(subclass)
click to toggle source
# File lib/multi-tk.rb, line 969 def self.inherited(subclass) # trust if on ThreadGroup::Default or @@DEFAULT_MASTER's ThreadGroup if @@IP_TABLE[Thread.current.group] == @@DEFAULT_MASTER begin class << subclass self.methods.each{|m| name = m.to_s begin unless name == '__id__' || name == '__send__' || name == 'freeze' undef_method(m) end rescue Exception # ignore all exceptions end } end ensure subclass.freeze fail SecurityError, "cannot create subclass of MultiTkIp on a untrusted ThreadGroup" end end end
init_ip_env(script = nil, &block)
click to toggle source
# File lib/multi-tk.rb, line 1776 def self.init_ip_env(script = nil, &block) script ||= block @@INIT_IP_ENV << script if __getip.slave? begin raise SecurityError, "slave-IP has no permission initializing IP env" rescue SecurityError => e #p e.backtrace # Is called on a Ruby/Tk library? caller_info = e.backtrace[1] if caller_info =~ %r{^#{MultiTkIp::BASE_DIR}/(tk|tkextlib)/[^:]+\.rb:} # Probably, caller is a Ruby/Tk library --> allow creating else raise e end end end # @@IP_TABLE.each{|tg, ip| # ip._init_ip_env(script) # } @@DEFAULT_MASTER.__init_ip_env__(@@IP_TABLE, script) end
init_ip_internal()
click to toggle source
# File lib/multi-tk.rb, line 1824 def self.init_ip_internal __getip._init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS) end
ip_name()
click to toggle source
# File lib/multi-tk.rb, line 1625 def self.ip_name __getip.ip_name end
mainloop(check_root = true)
click to toggle source
# File lib/multi-tk.rb, line 787 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
manipulable?()
click to toggle source
# File lib/multi-tk.rb, line 1656 def self.manipulable? true end
master?()
click to toggle source
# File lib/multi-tk.rb, line 1590 def self.master? __getip.master? end
method_missing(m, *args)
click to toggle source
# File lib/multi-tk.rb, line 1767 def self.method_missing(m, *args) MultiTkIp.tk_object_table(@id).__send__(m, *args) end
mutex()
click to toggle source
# File lib/multi-tk.rb, line 1764 def self.mutex @mutex end
new(ip, cmd)
click to toggle source
# File lib/multi-tk.rb, line 186 def initialize(ip, cmd) @ip = ip @safe = safe = 0 # @cmd = cmd cmd = MultiTkIp._proc_on_safelevel(&cmd) @cmd = proc{|*args| cmd.call(safe, *args)} self.freeze end
Also aliased as: __new
new(target, ret)
click to toggle source
Calls superclass method
# File lib/multi-tk.rb, line 875 def self.new(target, ret) obj = super() obj.target = target obj.ret = ret obj end
new_master(_safe=nil, keys={}, &blk)
click to toggle source
# File lib/multi-tk.rb, line 1486 def new_master(_safe=nil, keys={}, &blk) if MultiTkIp::WITH_RUBY_VM #### TODO !!!!!! fail RuntimeError, 'sorry, still not support multiple master-interpreters on RubyVM' end if safe.kind_of?(Hash) keys = safe elsif safe.kind_of?(Integer) raise ArgumentError, "unexpected argument(s)" unless keys.kind_of?(Hash) if !keys.key?(:safe) && !keys.key?('safe') keys[:safe] = safe end elsif safe == nil # do nothing else raise ArgumentError, "unexpected argument(s)" end ip = __new(__getip, nil, keys) if block_given? ip._proc_on_safelevel(&blk).call(0) end ip end
Also aliased as: new
new_safe_slave(safe=1, keys={}, &blk)
click to toggle source
# File lib/multi-tk.rb, line 1537 def new_safe_slave(safe=1, keys={}, &blk) if safe.kind_of?(Hash) keys = safe elsif safe.kind_of?(Integer) raise ArgumentError, "unexpected argument(s)" unless keys.kind_of?(Hash) if !keys.key?(:safe) && !keys.key?('safe') keys[:safe] = safe end else raise ArgumentError, "unexpected argument(s)" end ip = __new(__getip, true, keys) if block_given? ip._proc_on_safelevel(&blk).call(0) end ip end
Also aliased as: new_safeTk
new_slave(safe=nil, keys={}, &blk)
click to toggle source
# File lib/multi-tk.rb, line 1515 def new_slave(safe=nil, keys={}, &blk) if safe.kind_of?(Hash) keys = safe elsif safe.kind_of?(Integer) raise ArgumentError, "unexpected argument(s)" unless keys.kind_of?(Hash) if !keys.key?(:safe) && !keys.key?('safe') keys[:safe] = safe end elsif safe == nil # do nothing else raise ArgumentError, "unexpected argument(s)" end ip = __new(__getip, false, keys) if block_given? ip._proc_on_safelevel(&blk).call(0) end ip end
Also aliased as: new_trusted_slave
path()
click to toggle source
# File lib/multi-tk.rb, line 1619 def self.path __getip.path end
remove_tk_procs(*names)
click to toggle source
# File lib/multi-tk.rb, line 1812 def self.remove_tk_procs(*names) names.each{|name| name = name.to_s @@ADD_TK_PROCS.delete_if{|elem| elem.kind_of?(Array) && elem[0].to_s == name } } @@IP_TABLE.each{|tg, ip| ip._remove_tk_procs(*names) } end
safe_level()
click to toggle source
# File lib/multi-tk.rb, line 330 def self.safe_level 0 end
safe_level=(safe)
click to toggle source
# File lib/multi-tk.rb, line 324 def self.safe_level=(safe) 0 end
set_safe_level(safe)
click to toggle source
# File lib/multi-tk.rb, line 321 def self.set_safe_level(safe) 0 end
slave?()
click to toggle source
# File lib/multi-tk.rb, line 1597 def self.slave? not self.master? end
slaves(all = false)
click to toggle source
# File lib/multi-tk.rb, line 1647 def self.slaves(all = false) __getip.slaves(all) end
table()
click to toggle source
# File lib/multi-tk.rb, line 1446 def self.table @table end
tk_cmd_tbl()
click to toggle source
# File lib/multi-tk.rb, line 1733 def self.tk_cmd_tbl @@TK_CMD_TBL end
tk_object_table(id)
click to toggle source
# File lib/multi-tk.rb, line 1739 def self.tk_object_table(id) __getip._tk_table_list[id] end
tk_windows()
click to toggle source
# File lib/multi-tk.rb, line 1736 def self.tk_windows __getip._tk_windows end
to_eval()
click to toggle source
# File lib/multi-tk.rb, line 1631 def self.to_eval __getip.to_eval end
Private Class Methods
Public Instance Methods
__create_safe_slave_obj(safe_opts, app_name, tk_opts)
click to toggle source
# File lib/multi-tk.rb, line 1176 def __create_safe_slave_obj(safe_opts, app_name, tk_opts) raise SecurityError, "no permission to manipulate" unless self.manipulable? # safe interpreter ip_name = _create_slave_ip_name slave_ip = @interp.create_slave(ip_name, true) slave_ip.instance_eval{ @force_default_encoding ||= [false] @encoding ||= [nil] def @encoding.to_s; self.join(nil); end } @slave_ip_tbl[ip_name] = slave_ip def slave_ip.safe_base? true end @interp._eval("::safe::interpInit #{ip_name}") slave_ip._invoke('set', 'argv0', app_name) if app_name.kind_of?(String) if tk_opts tk_opts = __check_safetk_optkeys(tk_opts) if tk_opts.key?('use') @slave_ip_top[ip_name] = '' else tk_opts, top_path = __create_safetk_frame(slave_ip, ip_name, app_name, tk_opts) @slave_ip_top[ip_name] = top_path end @interp._eval("::safe::loadTk #{ip_name} #{_keys2opts(tk_opts)}") @interp._invoke('__replace_slave_tk_commands__', ip_name) else @slave_ip_top[ip_name] = nil end if safe_opts.key?('deleteHook') || safe_opts.key?(:deleteHook) @interp._eval("::safe::interpConfigure #{ip_name} " + _keys2opts(safe_opts)) else @interp._eval("::safe::interpConfigure #{ip_name} " + _keys2opts(safe_opts) + '-deleteHook {' + TkComm._get_eval_string(proc{|slave| self._default_delete_hook(slave) }) + '}') end [slave_ip, ip_name] end
__create_trusted_slave_obj(name, keys)
click to toggle source
# File lib/multi-tk.rb, line 1225 def __create_trusted_slave_obj(name, keys) raise SecurityError, "no permission to manipulate" unless self.manipulable? ip_name = _create_slave_ip_name slave_ip = @interp.create_slave(ip_name, false) slave_ip.instance_eval{ @force_default_encoding ||= [false] @encoding ||= [nil] def @encoding.to_s; self.join(nil); end } slave_ip._invoke('set', 'argv0', name) if name.kind_of?(String) slave_ip._invoke('set', 'argv', _keys2opts(keys)) @interp._invoke('load', '', 'Tk', ip_name) @interp._invoke('__replace_slave_tk_commands__', ip_name) @slave_ip_tbl[ip_name] = slave_ip [slave_ip, ip_name] end
__pseudo_toplevel()
click to toggle source
instance method
# File lib/multi-tk.rb, line 1849 def __pseudo_toplevel ip = MultiTkIp.__getip (ip == @@DEFAULT_MASTER || ip == self) && self.__pseudo_toplevel_evaluable? && @pseudo_toplevel[1] end
__pseudo_toplevel=(m)
click to toggle source
# File lib/multi-tk.rb, line 1855 def __pseudo_toplevel=(m) unless (Thread.current.group == ThreadGroup::Default && MultiTkIp.__getip == @@DEFAULT_MASTER) fail SecurityError, "no permission to manipulate" end # if m.kind_of?(Module) && m.respond_to?(:pseudo_toplevel_evaluable?) if m.respond_to?(:pseudo_toplevel_evaluable?) @pseudo_toplevel[0] = true @pseudo_toplevel[1] = m else fail ArgumentError, 'fail to set pseudo-toplevel' end self end
__pseudo_toplevel_evaluable=(mode)
click to toggle source
# File lib/multi-tk.rb, line 1879 def __pseudo_toplevel_evaluable=(mode) unless (Thread.current.group == ThreadGroup::Default && MultiTkIp.__getip == @@DEFAULT_MASTER) fail SecurityError, "no permission to manipulate" end @pseudo_toplevel[0] = (mode)? true: false end
__pseudo_toplevel_evaluable?()
click to toggle source
# File lib/multi-tk.rb, line 1871 def __pseudo_toplevel_evaluable? begin @pseudo_toplevel[0] && @pseudo_toplevel[1].pseudo_toplevel_evaluable? rescue Exception false end end
_add_new_tables()
click to toggle source
# File lib/multi-tk.rb, line 1683 def _add_new_tables (@@TK_TABLE_LIST.size - @tk_table_list.size).times{ @tk_table_list << {} } end
_add_tk_procs(name, args, body)
click to toggle source
# File lib/multi-tk.rb, line 1693 def _add_tk_procs(name, args, body) return if slave? @interp._invoke('proc', name, args, body) if args && body @interp._invoke('interp', 'slaves').split.each{|slave| @interp._invoke('interp', 'alias', slave, name, '', name) } end
_create_slave_object(keys={})
click to toggle source
# File lib/multi-tk.rb, line 1245 def _create_slave_object(keys={}) raise SecurityError, "no permission to manipulate" unless self.manipulable? ip = MultiTkIp.new_slave(self, keys={}) @slave_ip_tbl[ip.name] = ip end
_default_delete_hook(slave)
click to toggle source
# File lib/multi-tk.rb, line 1408 def _default_delete_hook(slave) raise SecurityError, "no permission to manipulate" unless self.manipulable? @slave_ip_tbl.delete(slave) top = @slave_ip_top.delete(slave) if top.kind_of?(String) # call default hook of safetk.tcl (ignore exceptions) if top == '' begin @interp._eval("::safe::disallowTk #{slave}") rescue warn("Warning: fail to call '::safe::disallowTk'") if $DEBUG end else # toplevel path begin @interp._eval("::safe::tkDelete {} #{top} #{slave}") rescue warn("Warning: fail to call '::safe::tkDelete'") if $DEBUG begin @interp._eval("destroy #{top}") rescue warn("Warning: fail to destroy toplevel") if $DEBUG end end end end end
_destroy_slaves_of_slaveIP(ip)
click to toggle source
# File lib/multi-tk.rb, line 345 def _destroy_slaves_of_slaveIP(ip) unless ip.deleted? # ip._split_tklist(ip._invoke('interp', 'slaves')).each{|name| ip._split_tklist(ip._invoke_without_enc('interp', 'slaves')).each{|name| name = _fromUTF8(name) begin # ip._eval_without_enc("#{name} eval {foreach i [after info] {after cancel $i}}") after_ids = ip._eval_without_enc("#{name} eval {after info}") ip._eval_without_enc("#{name} eval {foreach i {#{after_ids}} {after cancel $i}}") rescue Exception end begin # ip._invoke('interp', 'eval', name, 'destroy', '.') ip._invoke(name, 'eval', 'destroy', '.') rescue Exception end # safe_base? if ip._eval_without_enc("catch {::safe::interpConfigure #{name}}") == '0' begin ip._eval_without_enc("::safe::interpDelete #{name}") rescue Exception end end =begin if ip._invoke('interp', 'exists', name) == '1' begin ip._invoke(name, 'eval', 'exit') rescue Exception end end =end unless ip.deleted? if ip._invoke('interp', 'exists', name) == '1' begin ip._invoke('interp', 'delete', name) rescue Exception end end end } end end
_init_ip_env(script)
click to toggle source
# File lib/multi-tk.rb, line 1689 def _init_ip_env(script) self.eval_proc{script.call(self)} end
_init_ip_internal(init_ip_env, add_tk_procs)
click to toggle source
# File lib/multi-tk.rb, line 1717 def _init_ip_internal(init_ip_env, add_tk_procs) #init_ip_env.each{|script| self.eval_proc{script.call(self)}} init_ip_env.each{|script| self._init_ip_env(script)} add_tk_procs.each{|name, args, body| if master? @interp._invoke('proc', name, args, body) if args && body else @set_alias_proc.call(name) end } end
_ip_id_()
click to toggle source
# File lib/multi-tk.rb, line 1454 def _ip_id_ # for RemoteTkIp '' end
_receiver_mainloop(check_root)
click to toggle source
# File lib/multi-tk.rb, line 593 def _receiver_mainloop(check_root) if @evloop_thread[0] && @evloop_thread[0].alive? @evloop_thread[0] else @evloop_thread[0] = Thread.new{ while !@interp.deleted? #if check_root # inf = @interp._invoke_without_enc('info', 'command', '.') # break if !inf.kind_of?(String) || inf != '.' #end break if check_root && !@interp.has_mainwindow? sleep 0.5 end } @evloop_thread[0] end end
_remove_tk_procs(*names)
click to toggle source
# File lib/multi-tk.rb, line 1701 def _remove_tk_procs(*names) 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 } } end
_tk_cmd_tbl()
click to toggle source
# File lib/multi-tk.rb, line 1669 def _tk_cmd_tbl tbl = {} MultiTkIp.tk_cmd_tbl.each{|id, ent| tbl[id] = ent if ent.ip == self } tbl end
_tk_table_list()
click to toggle source
# File lib/multi-tk.rb, line 1679 def _tk_table_list @tk_table_list end
_tk_windows()
click to toggle source
# File lib/multi-tk.rb, line 1675 def _tk_windows @tk_windows end
alive?()
click to toggle source
# File lib/multi-tk.rb, line 1601 def alive? raise SecurityError, "no permission to manipulate" unless self.manipulable? begin return false unless @cmd_receiver.alive? return false if @interp.deleted? return false if @interp._invoke('interp', 'exists', '') == '0' rescue Exception return false end true end
call(*args)
click to toggle source
# File lib/multi-tk.rb, line 198 def call(*args) unless @ip.deleted? current = Thread.current backup_ip = current[:callback_ip] current[:callback_ip] = @ip begin ret = @ip.cb_eval(@cmd, *args) fail ret if ret.kind_of?(Exception) ret rescue TkCallbackBreak, TkCallbackContinue => e fail e rescue SecurityError => e # in 'exit', 'exit!', and 'abort' : security error --> delete IP if e.backtrace[0] =~ /^(.+?):(\d+):in `(exit|exit!|abort)'/ @ip.delete elsif @ip.safe? if @ip.respond_to?(:cb_error) @ip.cb_error(e) else nil # ignore end else fail e end rescue Exception => e fail e if e.message =~ /^TkCallback/ if @ip.safe? if @ip.respond_to?(:cb_error) @ip.cb_error(e) else nil # ignore end else fail e end ensure current[:callback_ip] = backup_ip end end end
cb_error(e)
click to toggle source
# File lib/multi-tk.rb, line 307 def cb_error(e) if @cb_error_proc[0].respond_to?(:call) @cb_error_proc[0].call(e) end end
cb_eval(cmd, *args)
click to toggle source
# File lib/multi-tk.rb, line 1838 def cb_eval(cmd, *args) self.eval_callback(*args, &_proc_on_safelevel{|*params| TkComm._get_eval_string(TkUtil.eval_cmd(cmd, *params)) }) end
inspect()
click to toggle source
# File lib/multi-tk.rb, line 195 def inspect cmd.inspect end
ip_name()
click to toggle source
# File lib/multi-tk.rb, line 1622 def ip_name @ip_name || '' end
manipulable?()
click to toggle source
# File lib/multi-tk.rb, line 1651 def manipulable? return true if (Thread.current.group == ThreadGroup::Default) ip = MultiTkIp.__getip (ip == self) || ip._is_master_of?(@interp) end
master?()
click to toggle source
# File lib/multi-tk.rb, line 1583 def master? if @ip_name false else true end end
mutex()
click to toggle source
# File lib/multi-tk.rb, line 92 def mutex; @mutex; end
path()
click to toggle source
# File lib/multi-tk.rb, line 1616 def path @ip_name || '' end
running_mainloop?()
click to toggle source
# File lib/multi-tk.rb, line 341 def running_mainloop? @wait_on_mainloop[1] > 0 end
safe_level()
click to toggle source
# File lib/multi-tk.rb, line 327 def safe_level 0 end
safe_level=(safe)
click to toggle source
# File lib/multi-tk.rb, line 318 def safe_level=(safe) 0 end
set_cb_error(cmd = nil, &block)
click to toggle source
# File lib/multi-tk.rb, line 303 def set_cb_error(cmd = nil, &block) @cb_error_proc[0] = cmd || block end
set_safe_level(safe)
click to toggle source
# File lib/multi-tk.rb, line 315 def set_safe_level(safe) 0 end
slave?()
click to toggle source
# File lib/multi-tk.rb, line 1594 def slave? not master? end
slaves(all = false)
click to toggle source
# File lib/multi-tk.rb, line 1635 def slaves(all = false) raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp','slaves').split.map!{|name| if @slave_ip_tbl.key?(name) @slave_ip_tbl[name] elsif all name else nil end }.compact! end
to_eval()
click to toggle source
# File lib/multi-tk.rb, line 1628 def to_eval @ip_name || '' end
wait_on_mainloop=(bool)
click to toggle source
# File lib/multi-tk.rb, line 337 def wait_on_mainloop=(bool) @wait_on_mainloop[0] = bool end
wait_on_mainloop?()
click to toggle source
# File lib/multi-tk.rb, line 334 def wait_on_mainloop? @wait_on_mainloop[0] end
Protected Instance Methods
_is_master_of?(tcltkip_obj)
click to toggle source
# File lib/multi-tk.rb, line 1660 def _is_master_of?(tcltkip_obj) tcltkip_obj.slave_of?(@interp) end
Private Instance Methods
__check_safetk_optkeys(optkeys)
click to toggle source
# File lib/multi-tk.rb, line 1040 def __check_safetk_optkeys(optkeys) # based on 'safetk.tcl' new_keys = {} optkeys.each{|k,v| new_keys[k.to_s] = v} # check 'display' if !new_keys.key?('display') begin #new_keys['display'] = @interp._invoke('winfo screen .') new_keys['display'] = @interp._invoke('winfo', 'screen', '.') rescue if ENV[DISPLAY] new_keys['display'] = ENV[DISPLAY] elsif !new_keys.key?('use') warn "Warning: no screen info or ENV[DISPLAY], so use ':0.0'" new_keys['display'] = ':0.0' end end end # check 'use' if new_keys.key?('use') # given 'use' case new_keys['use'] when TkWindow new_keys['use'] = TkWinfo.id(new_keys['use']) #assoc_display = @interp._eval('winfo screen .') assoc_display = @interp._invoke('winfo', 'screen', '.') when /^\..*/ new_keys['use'] = @interp._invoke('winfo', 'id', new_keys['use']) assoc_display = @interp._invoke('winfo', 'screen', new_keys['use']) else begin pathname = @interp._invoke('winfo', 'pathname', new_keys['use']) assoc_display = @interp._invoke('winfo', 'screen', pathname) rescue assoc_display = new_keys['display'] end end # match display? if assoc_display != new_keys['display'] if optkeys.key?(:display) || optkeys.key?('display') fail RuntimeError, "conflicting 'display'=>#{new_keys['display']} " + "and display '#{assoc_display}' on 'use'=>#{new_keys['use']}" else new_keys['display'] = assoc_display end end end # return new_keys end
__create_safetk_frame(slave_ip, slave_name, app_name, keys)
click to toggle source
# File lib/multi-tk.rb, line 1097 def __create_safetk_frame(slave_ip, slave_name, app_name, keys) # display option is used by ::safe::loadTk loadTk_keys = {} loadTk_keys['display'] = keys['display'] dup_keys = keys.dup # keys for toplevel : allow followings toplevel_keys = {} ['height', 'width', 'background', 'menu'].each{|k| toplevel_keys[k] = dup_keys.delete(k) if dup_keys.key?(k) } toplevel_keys['classname'] = 'SafeTk' toplevel_keys['screen'] = dup_keys.delete('display') # other keys used by pack option of container frame # create toplevel widget begin top = TkToplevel.new(toplevel_keys) rescue NameError => e fail e unless @interp.safe? fail SecurityError, "unable create toplevel on the safe interpreter" end msg = "Untrusted Ruby/Tk applet (#{slave_name})" if app_name.kind_of?(String) top.title "#{app_name} (#{slave_name})" else top.title msg end # procedure to delete slave interpreter slave_delete_proc = proc{ unless slave_ip.deleted? #if slave_ip._invoke('info', 'command', '.') != "" # slave_ip._invoke('destroy', '.') #end #slave_ip.delete slave_ip._eval_without_enc('exit') end begin top.destroy if top.winfo_exist? rescue # ignore end } tag = TkBindTag.new.bind('Destroy', slave_delete_proc) top.bindtags = top.bindtags.unshift(tag) # create control frame TkFrame.new(top, :bg=>'red', :borderwidth=>3, :relief=>'ridge') {|fc| fc.bindtags = fc.bindtags.unshift(tag) TkFrame.new(fc, :bd=>0){|f| TkButton.new(f, :text=>'Delete', :bd=>1, :padx=>2, :pady=>0, :highlightthickness=>0, :command=>slave_delete_proc ).pack(:side=>:right, :fill=>:both) f.pack(:side=>:right, :fill=>:both, :expand=>true) } TkLabel.new(fc, :text=>msg, :padx=>2, :pady=>0, :anchor=>:w).pack(:side=>:left, :fill=>:both, :expand=>true) fc.pack(:side=>:bottom, :fill=>:x) } # container frame for slave interpreter dup_keys['fill'] = :both unless dup_keys.key?('fill') dup_keys['expand'] = true unless dup_keys.key?('expand') c = TkFrame.new(top, :container=>true).pack(dup_keys) c.bind('Destroy', proc{top.destroy}) # return keys loadTk_keys['use'] = TkWinfo.id(c) [loadTk_keys, top.path] end
_check_and_return(thread, exception, wait=0)
click to toggle source
# File lib/multi-tk.rb, line 251 def _check_and_return(thread, exception, wait=0) unless thread unless exception.kind_of?(MultiTkIp_OK) msg = "#{exception.class}: #{exception.message}" if @interp.deleted? warn("Warning (#{self}): " + msg) return nil end if safe? warn("Warning (#{self}): " + msg) if $DEBUG return nil end begin @interp._eval_without_enc(@interp._merge_tklist('bgerror', msg)) rescue Exception warn("Warning (#{self}): " + msg) end end return nil end if wait == 0 # no wait Thread.pass if thread.stop? thread.raise exception end return thread end # wait to stop the caller thread wait.times{ if thread.stop? # ready to send exception thread.raise exception return thread end # wait Thread.pass } # unexpected error thread.raise RuntimeError, "the thread may not wait for the return value" return thread end
_create_receiver_and_watchdog(lvl = 0)
click to toggle source
# File lib/multi-tk.rb, line 611 def _create_receiver_and_watchdog(lvl = 0) lvl = 0 # command-procedures receiver receiver = Thread.new(lvl){|_safe_level| last_thread = {} loop do break if @interp.deleted? thread, cmd, *args = @cmd_queue.deq if thread == @system # control command case cmd when 'call_mainloop' thread = args.shift _check_and_return(thread, MultiTkIp_OK.new(_receiver_mainloop(*args))) else # ignore end else # procedure last_thread[thread] = _receiver_eval_proc(last_thread[thread], 0, thread, cmd, *args) end end } # watchdog of receiver watchdog = Thread.new{ begin loop do sleep 1 if @interp.deleted? receiver.kill @cmd_queue.close end break unless receiver.alive? end rescue Exception # ignore all kind of Exception end # receiver is dead retry_count = 3 loop do Thread.pass begin thread, _, *_ = @cmd_queue.deq(true) # non-block rescue ThreadError # queue is empty retry_count -= 1 break if retry_count <= 0 sleep 0.5 retry end next unless thread if thread.alive? if @interp.deleted? thread.raise RuntimeError, 'the interpreter is already deleted' else thread.raise RuntimeError, 'the interpreter no longer receives command procedures' end end end } # return threads [receiver, watchdog] end
_create_slave_ip_name()
click to toggle source
# File lib/multi-tk.rb, line 1029 def _create_slave_ip_name @@SLAVE_IP_ID.mutex.synchronize{ name = @@SLAVE_IP_ID.join('') @@SLAVE_IP_ID[1].succ! name.freeze } end
_keys2opts(src_keys)
click to toggle source
# File lib/multi-tk.rb, line 243 def _keys2opts(src_keys) return nil if src_keys == nil keys = {}; src_keys.each{|k, v| keys[k.to_s] = v} #keys.collect{|k,v| "-#{k} #{v}"}.join(' ') keys.collect{|k,v| "-#{k} #{TclTkLib._conv_listelement(TkComm::_get_eval_string(v))}"}.join(' ') end
_parse_slaveopts(keys)
click to toggle source
# File lib/multi-tk.rb, line 1002 def _parse_slaveopts(keys) name = nil safe = false safe_opts = {} tk_opts = {} keys.each{|k,v| k_str = k.to_s if k_str == 'name' name = v elsif k_str == 'safe' safe = v elsif @@SAFE_OPT_LIST.member?(k_str) safe_opts[k_str] = v else tk_opts[k_str] = v end } if keys['without_tk'] || keys[:without_tk] [name, safe, safe_opts, nil] else [name, safe, safe_opts, tk_opts] end end
_receiver_eval_proc(last_thread, _safe_level, thread, cmd, *args)
click to toggle source
# File lib/multi-tk.rb, line 573 def _receiver_eval_proc(last_thread, _safe_level, thread, cmd, *args) if thread Thread.new{ last_thread.join if last_thread unless @interp.deleted? _receiver_eval_proc_core(0, thread, cmd, *args) end } else Thread.new{ unless @interp.deleted? _receiver_eval_proc_core(0, thread, cmd, *args) end } last_thread end end
_receiver_eval_proc_core(_safe_level, thread, cmd, *args)
click to toggle source
# File lib/multi-tk.rb, line 389 def _receiver_eval_proc_core(_safe_level, thread, cmd, *args) begin normal_ret = false ret = catch(:IRB_EXIT) do # IRB hack retval = cmd.call(0, *args) normal_ret = true retval end unless normal_ret # catch IRB_EXIT exit(ret) end ret rescue SystemExit => e # delete IP unless @interp.deleted? @slave_ip_tbl.each{|name, subip| _destroy_slaves_of_slaveIP(subip) begin # subip._eval_without_enc("foreach i [after info] {after cancel $i}") after_ids = subip._eval_without_enc("after info") subip._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}") rescue Exception end =begin begin subip._invoke('destroy', '.') unless subip.deleted? rescue Exception end =end # safe_base? if @interp._eval_without_enc("catch {::safe::interpConfigure #{name}}") == '0' begin @interp._eval_without_enc("::safe::interpDelete #{name}") rescue Exception else next if subip.deleted? end end if subip.respond_to?(:safe_base?) && subip.safe_base? && !subip.deleted? # do 'exit' to call the delete_hook procedure begin subip._eval_without_enc('exit') rescue Exception end else begin subip.delete unless subip.deleted? rescue Exception end end } begin # @interp._eval_without_enc("foreach i [after info] {after cancel $i}") after_ids = @interp._eval_without_enc("after info") @interp._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}") rescue Exception end begin @interp._invoke('destroy', '.') unless @interp.deleted? rescue Exception end if @safe_base && !@interp.deleted? # do 'exit' to call the delete_hook procedure @interp._eval_without_enc('exit') else @interp.delete unless @interp.deleted? end end if e.backtrace[0] =~ /^(.+?):(\d+):in `(exit|exit!|abort)'/ _check_and_return(thread, MultiTkIp_OK.new($3 == 'exit')) else _check_and_return(thread, MultiTkIp_OK.new(nil)) end # if master? && !safe? && allow_ruby_exit? if !@interp.deleted? && master? && !safe? && allow_ruby_exit? =begin ObjectSpace.each_object(TclTkIp){|obj| obj.delete unless obj.deleted? } =end #exit(e.status) fail e end # break rescue SecurityError => e # in 'exit', 'exit!', and 'abort' : security error --> delete IP if e.backtrace[0] =~ /^(.+?):(\d+):in `(exit|exit!|abort)'/ ret = ($3 == 'exit') unless @interp.deleted? @slave_ip_tbl.each{|name, subip| _destroy_slaves_of_slaveIP(subip) begin # subip._eval_without_enc("foreach i [after info] {after cancel $i}") after_ids = subip._eval_without_enc("after info") subip._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}") rescue Exception end =begin begin subip._invoke('destroy', '.') unless subip.deleted? rescue Exception end =end # safe_base? if @interp._eval_without_enc("catch {::safe::interpConfigure #{name}}") == '0' begin @interp._eval_without_enc("::safe::interpDelete #{name}") rescue Exception else next if subip.deleted? end end if subip.respond_to?(:safe_base?) && subip.safe_base? && !subip.deleted? # do 'exit' to call the delete_hook procedure begin subip._eval_without_enc('exit') rescue Exception end else begin subip.delete unless subip.deleted? rescue Exception end end } begin # @interp._eval_without_enc("foreach i [after info] {after cancel $i}") after_ids = @interp._eval_without_enc("after info") @interp._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}") rescue Exception end =begin begin @interp._invoke('destroy', '.') unless @interp.deleted? rescue Exception end =end if @safe_base && !@interp.deleted? # do 'exit' to call the delete_hook procedure @interp._eval_without_enc('exit') else @interp.delete unless @interp.deleted? end end _check_and_return(thread, MultiTkIp_OK.new(ret)) # break else # raise security error _check_and_return(thread, e) end rescue Exception => e # raise exception begin bt = _toUTF8(e.backtrace.join("\n")) 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 begin @interp._set_global_var('errorInfo', bt) rescue Exception end _check_and_return(thread, e) else # no exception _check_and_return(thread, MultiTkIp_OK.new(ret)) end end