module TkCore

start Tk which depends on MultiTkIp

Constants

EventFlag
INTERP

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


evaluate a procedure on the proper interpreter


event loop all master/slave IPs are controlled by only one event-loop


depend on TclTkIp


interp command support


Safe Base

manipulating safe interpreter





INTERP_MUTEX
INTERP_ROOT_CHECK
INTERP_THREAD
INTERP_THREAD_STATUS
RUN_EVENTLOOP_ON_MAIN_THREAD

*** KNOWN BUG ***

Main event loop thread of TkAqua (> Tk8.4.9) must be the main
application thread. So, ruby1.9 users must call Tk.mainloop on
the main application thread.

*** ADD (2009/05/10) ***

In some cases (I don't know the description of conditions),
TkAqua 8.4.7 has a same kind of hang-up trouble.
So, if 8.4.7 or later, set RUN_EVENTLOOP_ON_MAIN_THREAD to true.
When you want to control this mode, please call the following
(set true/false as you want) before "require 'tk'".
----------------------------------------------------------
module TkCore; RUN_EVENTLOOP_ON_MAIN_THREAD = true; end
----------------------------------------------------------

*** ADD (2010/07/05) ***

The value of TclTkLib::WINDOWING_SYSTEM is defined at compiling.
If it is inconsistent with linked DLL, please call the following
before "require 'tk'".
----------------------------------------------------------
require 'tcltklib'
module TclTkLib
  remove_const :WINDOWING_SYSTEM
  WINDOWING_SYSTEM = 'x11' # or 'aqua'
end
----------------------------------------------------------
WIDGET_DESTROY_HOOK
WITH_ENCODING
WITH_RUBY_VM

Public Class Methods

callback(*arg) click to toggle source
# File lib/tk.rb, line 1576
def TkCore.callback(*arg)
  begin
    if TkCore::INTERP.tk_cmd_tbl.kind_of?(Hash)
      #TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg)
      normal_ret = false
      ret = catch(:IRB_EXIT) do  # IRB hack
        retval = TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg)
        normal_ret = true
        retval
      end
      unless normal_ret
        # catch IRB_EXIT
        exit(ret)
      end
      ret
    end
  rescue SystemExit=>e
    exit(e.status)
  rescue Interrupt=>e
    fail(e)
  rescue Exception => e
    begin
      msg = _toUTF8(e.class.inspect) + ': ' +
            _toUTF8(e.message) + "\n" +
            "\n---< backtrace of Ruby side >-----\n" +
            _toUTF8(e.backtrace.join("\n")) +
            "\n---< backtrace of Tk side >-------"
      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" +
            e.backtrace.join("\n") +
            "\n---< backtrace of Tk side >-------"
    end
    # TkCore::INTERP._set_global_var('errorInfo', msg)
    # fail(e)
    fail(e, msg)
  end
end
inspect() click to toggle source
# File lib/tk.rb, line 1373
def inspect
  sprintf("#<Class(TkCallbackEntry):%0x>", self.__id__)
end
Also aliased as: to_s
new(ip, cmd) click to toggle source
# File lib/tk.rb, line 1379
def initialize(ip, cmd)
  @ip = ip
  @cmd = cmd
end
to_s()
Alias for: inspect

Public Instance Methods

_tk_call_to_list_core(depth, arg_enc, val_enc, *args) click to toggle source
# File lib/tk.rb, line 2050
def _tk_call_to_list_core(depth, arg_enc, val_enc, *args)
  args = _conv_args([], arg_enc, *args)
  val = _tk_call_core(false, *args)
  if !depth.kind_of?(Integer) || depth == 0
    tk_split_simplelist(val, false, val_enc)
  else
    tk_split_list(val, depth, false, val_enc)
  end
end
after(ms, cmd=nil, &block) click to toggle source
# File lib/tk.rb, line 1662
def after(ms, cmd=nil, &block)
  cmd ||= block
  cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret})
  after_id = tk_call_without_enc("after",ms,cmdid)
  after_id.instance_variable_set('@cmdid', cmdid)
  after_id
end
after_cancel(afterId) click to toggle source
# File lib/tk.rb, line 1678
def after_cancel(afterId)
  tk_call_without_enc('after','cancel',afterId)
  if (cmdid = afterId.instance_variable_get('@cmdid'))
    afterId.instance_variable_set('@cmdid', nil)
    uninstall_cmd(cmdid)
  end
  afterId
end
after_idle(cmd=nil, &block) click to toggle source
# File lib/tk.rb, line 1670
def after_idle(cmd=nil, &block)
  cmd ||= block
  cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret})
  after_id = tk_call_without_enc('after','idle',cmdid)
  after_id.instance_variable_set('@cmdid', cmdid)
  after_id
end
appname(name=None) click to toggle source
# File lib/tk.rb, line 1719
def appname(name=None)
  tk_call('tk', 'appname', name)
end
appsend(interp, async, *args) click to toggle source
# File lib/tk.rb, line 1727
def appsend(interp, async, *args)
  if async != true && async != false && async != nil
    args.unshift(async)
    async = false
  end
  if async
    tk_call('send', '-async', '--', interp, *args)
  else
    tk_call('send', '--', interp, *args)
  end
end
appsend_deny() click to toggle source
# File lib/tk.rb, line 1723
def appsend_deny
  tk_call('rename', 'send', '')
end
appsend_displayof(interp, win, async, *args) click to toggle source
# File lib/tk.rb, line 1752
def appsend_displayof(interp, win, async, *args)
  win = '.' if win == nil
  if async != true && async != false && async != nil
    args.unshift(async)
    async = false
  end
  if async
    tk_call('send', '-async', '-displayof', win, '--', interp, *args)
  else
    tk_call('send', '-displayor', win, '--', interp, *args)
  end
end
call(*args) click to toggle source
# File lib/tk.rb, line 1384
def call(*args)
  @ip.cb_eval(@cmd, *args)
end
callback_break() click to toggle source
# File lib/tk.rb, line 1564
def callback_break
  fail TkCallbackBreak, "Tk callback returns 'break' status"
end
callback_continue() click to toggle source
# File lib/tk.rb, line 1568
def callback_continue
  fail TkCallbackContinue, "Tk callback returns 'continue' status"
end
callback_return() click to toggle source
# File lib/tk.rb, line 1572
def callback_return
  fail TkCallbackReturn, "Tk callback returns 'return' status"
end
chooseColor(keys = nil) click to toggle source
# File lib/tk.rb, line 1942
def chooseColor(keys = nil)
  tk_call('tk_chooseColor', *hash_kv(keys))
end
chooseDirectory(keys = nil) click to toggle source
# File lib/tk.rb, line 1946
def chooseDirectory(keys = nil)
  tk_call('tk_chooseDirectory', *hash_kv(keys))
end
do_one_event(flag = TclTkLib::EventFlag::ALL) click to toggle source
# File lib/tk.rb, line 1868
def do_one_event(flag = TclTkLib::EventFlag::ALL)
  TclTkLib.do_one_event(flag)
end
event_generate(win, context, keys=nil) click to toggle source
# File lib/tk.rb, line 1909
def event_generate(win, context, keys=nil)
  #win = win.path if win.kind_of?(TkObject)
  if context.kind_of?(TkEvent::Event)
    context.generate(win, ((keys)? keys: {}))
  elsif keys
    tk_call_without_enc('event', 'generate', win,
                        "<#{tk_event_sequence(context)}>",
                        *hash_kv(keys, true))
  else
    tk_call_without_enc('event', 'generate', win,
                        "<#{tk_event_sequence(context)}>")
  end
  nil
end
getMultipleOpenFile(keys = nil) click to toggle source
# File lib/tk.rb, line 1931
def getMultipleOpenFile(keys = nil)
  simplelist(tk_call('tk_getOpenFile', '-multiple', '1', *hash_kv(keys)))
end
getMultipleSaveFile(keys = nil) click to toggle source
# File lib/tk.rb, line 1938
def getMultipleSaveFile(keys = nil)
  simplelist(tk_call('tk_getSaveFile', '-multiple', '1', *hash_kv(keys)))
end
getOpenFile(keys = nil) click to toggle source
# File lib/tk.rb, line 1928
def getOpenFile(keys = nil)
  tk_call('tk_getOpenFile', *hash_kv(keys))
end
getSaveFile(keys = nil) click to toggle source
# File lib/tk.rb, line 1935
def getSaveFile(keys = nil)
  tk_call('tk_getSaveFile', *hash_kv(keys))
end
get_eventloop_tick() click to toggle source
# File lib/tk.rb, line 1876
def get_eventloop_tick()
  TclTkLib.get_eventloop_tick
end
get_eventloop_weight() click to toggle source
# File lib/tk.rb, line 1892
def get_eventloop_weight()
  TclTkLib.get_eventloop_weight
end
get_no_event_wait() click to toggle source
# File lib/tk.rb, line 1884
def get_no_event_wait()
  TclTkLib.get_no_eventloop_wait
end
inactive() click to toggle source
# File lib/tk.rb, line 1706
def inactive
  Integer(tk_call_without_enc('tk', 'inactive'))
end
inactive_displayof(win) click to toggle source
# File lib/tk.rb, line 1709
def inactive_displayof(win)
  Integer(tk_call_without_enc('tk', 'inactive', '-displayof', win))
end
inspect() click to toggle source
# File lib/tk.rb, line 1387
def inspect
  sprintf("#<cb_entry:%0x>", self.__id__)
end
Also aliased as: to_s
ip_eval(cmd_string) click to toggle source
# File lib/tk.rb, line 1966
def ip_eval(cmd_string)
  _ip_eval_core(nil, cmd_string)
end
ip_eval_with_enc(cmd_string) click to toggle source
# File lib/tk.rb, line 1974
def ip_eval_with_enc(cmd_string)
  _ip_eval_core(true, cmd_string)
end
ip_eval_without_enc(cmd_string) click to toggle source
# File lib/tk.rb, line 1970
def ip_eval_without_enc(cmd_string)
  _ip_eval_core(false, cmd_string)
end
ip_invoke(*args) click to toggle source
# File lib/tk.rb, line 1994
def ip_invoke(*args)
  _ip_invoke_core(nil, *args)
end
ip_invoke_with_enc(*args) click to toggle source
# File lib/tk.rb, line 2002
def ip_invoke_with_enc(*args)
  _ip_invoke_core(true, *args)
end
ip_invoke_without_enc(*args) click to toggle source
# File lib/tk.rb, line 1998
def ip_invoke_without_enc(*args)
  _ip_invoke_core(false, *args)
end
is_mainloop?() click to toggle source
# File lib/tk.rb, line 1859
def is_mainloop?
  TclTkLib.mainloop_thread? == true
end
load_cmd_on_ip(tk_cmd) click to toggle source
def TkCore.callback(arg_str)
  # arg = tk_split_list(arg_str)
  arg = tk_split_simplelist(arg_str)
  #_get_eval_string(TkUtil.eval_cmd(Tk_CMDTBL[arg.shift], *arg))
  #_get_eval_string(TkUtil.eval_cmd(TkCore::INTERP.tk_cmd_tbl[arg.shift],
  #                        *arg))
  # TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg)
  begin
    TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg)
  rescue Exception => e
    raise(e, e.class.inspect + ': ' + e.message + "\n" +
             "\n---< backtrace of Ruby side >-----\n" +
             e.backtrace.join("\n") +
             "\n---< backtrace of Tk side >-------")
  end

#=begin # cb_obj = TkCore::INTERP.tk_cmd_tbl[arg.shift] # unless $DEBUG # cb_obj.call(*arg) # else # begin # raise 'check backtrace' # rescue # # ignore backtrace before 'callback' # pos = -($!.backtrace.size) # end # begin # cb_obj.call(*arg) # rescue # trace = $!.backtrace # raise $!, “n#{trace}: #{$!.message} (#{$!.class})n” + # “tfrom #{trace.join(”ntfrom “)}” # end # end #=end

end
# File lib/tk.rb, line 1658
def load_cmd_on_ip(tk_cmd)
  bool(tk_call('auto_load', tk_cmd))
end
mainloop(check_root = true) click to toggle source
# File lib/tk.rb, line 1783
def mainloop(check_root = true)
  if !TkCore::WITH_RUBY_VM
    TclTkLib.mainloop(check_root)

  elsif TkCore::RUN_EVENTLOOP_ON_MAIN_THREAD
    # if TclTkLib::WINDOWING_SYSTEM == 'aqua' &&
    #if TkCore::INTERP._invoke_without_enc('tk','windowingsystem')=='aqua' &&
    #    Thread.current != Thread.main &&
    #    (TclTkLib.get_version <=> [8,4,TclTkLib::RELEASE_TYPE::FINAL,9]) > 0
    #  raise RuntimeError,
    #       "eventloop on TkAqua ( > Tk8.4.9 ) works on the main thread only"
    #end
    if Thread.current != Thread.main
      raise RuntimeError, "Tk.mainloop is allowed on the main thread only"
    end
    TclTkLib.mainloop(check_root)

  else ### Ruby 1.9 !!!!!
    unless TkCore::INTERP.default_master?
      # [MultiTkIp] slave interp ?
      return TkCore::INTERP._thread_tkwait('window', '.') if check_root
    end

    # like as 1.8, withdraw a root widget before calling Tk.mainloop
    TkCore::INTERP._eval_without_enc('catch {unset __initial_state_of_rubytk__}')
    INTERP_THREAD.run

    begin
      TclTkLib.set_eventloop_window_mode(true)

      # force run the eventloop
      TkCore::INTERP._eval_without_enc('update')
      TkCore::INTERP._eval_without_enc('catch {set __initial_state_of_rubytk__}')
      INTERP_THREAD.run
      if check_root
        INTERP_MUTEX.synchronize{
          INTERP_ROOT_CHECK.wait(INTERP_MUTEX)
          status = INTERP_THREAD_STATUS.value
          if status && TkCore::INTERP.default_master?
            INTERP_THREAD_STATUS.value = nil
            raise status if status.kind_of?(Exception)
          end
        }
      else
        # INTERP_THREAD.value
        begin
          INTERP_THREAD.value
        rescue Exception => e
          raise e
        end
      end
    rescue Exception => e
      raise e
    ensure
      TclTkLib.set_eventloop_window_mode(false)
    end
  end
end
mainloop_exist?() click to toggle source
# File lib/tk.rb, line 1855
def mainloop_exist?
  TclTkLib.mainloop_thread? != nil
end
mainloop_thread?() click to toggle source
# File lib/tk.rb, line 1842
def mainloop_thread?
  # true  : current thread is mainloop
  # nil   : there is no mainloop
  # false : mainloop is running on the other thread
  #         ( At then, it is dangerous to call Tk interpreter directly. )
  if !TkCore::WITH_RUBY_VM || TkCore::RUN_EVENTLOOP_ON_MAIN_THREAD
    ### Ruby 1.9 !!!!!!!!!!!
    TclTkLib.mainloop_thread?
  else
    Thread.current == INTERP_THREAD
  end
end
mainloop_watchdog(check_root = true) click to toggle source
# File lib/tk.rb, line 1863
def mainloop_watchdog(check_root = true)
  # watchdog restarts mainloop when mainloop is dead
  TclTkLib.mainloop_watchdog(check_root)
end
messageBox(keys) click to toggle source
# File lib/tk.rb, line 1924
def messageBox(keys)
  tk_call('tk_messageBox', *hash_kv(keys))
end
rb_appsend(interp, async, *args) click to toggle source
# File lib/tk.rb, line 1739
def rb_appsend(interp, async, *args)
  if async != true && async != false && async != nil
    args.unshift(async)
    async = false
  end
  #args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"]/, '\\\\\&')}
  args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"\\]/, '\\\\\&')}
  # args.push(').to_s"')
  # appsend(interp, async, 'ruby "(', *args)
  args.push('}.call)"')
  appsend(interp, async, 'ruby "TkComm._get_eval_string(proc{', *args)
end
rb_appsend_displayof(interp, win, async, *args) click to toggle source
# File lib/tk.rb, line 1765
def rb_appsend_displayof(interp, win, async, *args)
  win = '.' if win == nil
  if async != true && async != false && async != nil
    args.unshift(async)
    async = false
  end
  #args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"]/, '\\\\\&')}
  args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"\\]/, '\\\\\&')}
  # args.push(').to_s"')
  # appsend_displayof(interp, win, async, 'ruby "(', *args)
  args.push('}.call)"')
  appsend(interp, win, async, 'ruby "TkComm._get_eval_string(proc{', *args)
end
reset_inactive() click to toggle source
# File lib/tk.rb, line 1712
def reset_inactive
  tk_call_without_enc('tk', 'inactive', 'reset')
end
reset_inactive_displayof(win) click to toggle source
# File lib/tk.rb, line 1715
def reset_inactive_displayof(win)
  tk_call_without_enc('tk', 'inactive', '-displayof', win, 'reset')
end
restart(app_name = nil, keys = {}) click to toggle source
# File lib/tk.rb, line 1896
def restart(app_name = nil, keys = {})
  TkCore::INTERP.init_ip_internal

  tk_call('set', 'argv0', app_name) if app_name
  if keys.kind_of?(Hash)
    # tk_call('set', 'argc', keys.size * 2)
    tk_call('set', 'argv', hash_kv(keys).join(' '))
  end

  INTERP.restart
  nil
end
scaling(scale=nil) click to toggle source
# File lib/tk.rb, line 1691
def scaling(scale=nil)
  if scale
    tk_call_without_enc('tk', 'scaling', scale)
  else
    Float(number(tk_call_without_enc('tk', 'scaling')))
  end
end
scaling_displayof(win, scale=nil) click to toggle source
# File lib/tk.rb, line 1698
def scaling_displayof(win, scale=nil)
  if scale
    tk_call_without_enc('tk', 'scaling', '-displayof', win, scale)
  else
    Float(number(tk_call_without_enc('tk', '-displayof', win, 'scaling')))
  end
end
set_eventloop_tick(timer_tick) click to toggle source
# File lib/tk.rb, line 1872
def set_eventloop_tick(timer_tick)
  TclTkLib.set_eventloop_tick(timer_tick)
end
set_eventloop_weight(loop_max, no_event_tick) click to toggle source
# File lib/tk.rb, line 1888
def set_eventloop_weight(loop_max, no_event_tick)
  TclTkLib.set_eventloop_weight(loop_max, no_event_tick)
end
set_no_event_wait(wait) click to toggle source
# File lib/tk.rb, line 1880
def set_no_event_wait(wait)
  TclTkLib.set_no_even_wait(wait)
end
tk_call(*args) click to toggle source
# File lib/tk.rb, line 2038
def tk_call(*args)
  _tk_call_core(nil, *args)
end
tk_call_to_list(*args) click to toggle source

private :_tk_call_to_list_core

# File lib/tk.rb, line 2061
def tk_call_to_list(*args)
  _tk_call_to_list_core(-1, nil, true, *args)
end
tk_call_to_list_with_enc(*args) click to toggle source
# File lib/tk.rb, line 2069
def tk_call_to_list_with_enc(*args)
  _tk_call_to_list_core(-1, true, true, *args)
end
tk_call_to_list_without_enc(*args) click to toggle source
# File lib/tk.rb, line 2065
def tk_call_to_list_without_enc(*args)
  _tk_call_to_list_core(-1, false, false, *args)
end
tk_call_to_simplelist(*args) click to toggle source
# File lib/tk.rb, line 2073
def tk_call_to_simplelist(*args)
  _tk_call_to_list_core(0, nil, true, *args)
end
tk_call_to_simplelist_with_enc(*args) click to toggle source
# File lib/tk.rb, line 2081
def tk_call_to_simplelist_with_enc(*args)
  _tk_call_to_list_core(0, true, true, *args)
end
tk_call_to_simplelist_without_enc(*args) click to toggle source
# File lib/tk.rb, line 2077
def tk_call_to_simplelist_without_enc(*args)
  _tk_call_to_list_core(0, false, false, *args)
end
tk_call_with_enc(*args) click to toggle source
# File lib/tk.rb, line 2046
def tk_call_with_enc(*args)
  _tk_call_core(true, *args)
end
tk_call_without_enc(*args) click to toggle source
# File lib/tk.rb, line 2042
def tk_call_without_enc(*args)
  _tk_call_core(false, *args)
end
to_s()
Alias for: inspect
windowingsystem() click to toggle source
# File lib/tk.rb, line 1687
def windowingsystem
  tk_call_without_enc('tk', 'windowingsystem')
end

Private Instance Methods

_ip_eval_core(enc_mode, cmd_string) click to toggle source
# File lib/tk.rb, line 1950
def _ip_eval_core(enc_mode, cmd_string)
  case enc_mode
  when nil
    res = INTERP._eval(cmd_string)
  when false
    res = INTERP._eval_without_enc(cmd_string)
  when true
    res = INTERP._eval_with_enc(cmd_string)
  end
  if  INTERP._return_value() != 0
    fail RuntimeError, res, error_at
  end
  return res
end
_ip_invoke_core(enc_mode, *args) click to toggle source
# File lib/tk.rb, line 1978
def _ip_invoke_core(enc_mode, *args)
  case enc_mode
  when false
    res = INTERP._invoke_without_enc(*args)
  when nil
    res = INTERP._invoke(*args)
  when true
    res = INTERP._invoke_with_enc(*args)
  end
  if  INTERP._return_value() != 0
    fail RuntimeError, res, error_at
  end
  return res
end
_tk_call_core(enc_mode, *args) click to toggle source
# File lib/tk.rb, line 2006
def _tk_call_core(enc_mode, *args)
  ### puts args.inspect if $DEBUG
  #args.collect! {|x|ruby2tcl(x, enc_mode)}
  #args.compact!
  #args.flatten!
  args = _conv_args([], enc_mode, *args)
  puts 'invoke args => ' + args.inspect if $DEBUG
  ### print "=> ", args.join(" ").inspect, "\n" if $DEBUG
  begin
    # res = INTERP._invoke(enc_mode, *args)
    res = _ip_invoke_core(enc_mode, *args)
    # >>>>>  _invoke returns a TAINTED string  <<<<<
  rescue NameError => err
    # err = $!
    begin
      args.unshift "unknown"
      #res = INTERP._invoke(enc_mode, *args)
      res = _ip_invoke_core(enc_mode, *args)
      # >>>>>  _invoke returns a TAINTED string  <<<<<
    rescue StandardError => err2
      fail err2 unless /^invalid command/ =~ err2.message
      fail err
    end
  end
  if  INTERP._return_value() != 0
    fail RuntimeError, res, error_at
  end
  ### print "==> ", res.inspect, "\n" if $DEBUG
  return res
end
info(*args) click to toggle source
# File lib/tk.rb, line 1779
def info(*args)
  tk_call('info', *args)
end