tcltklib and not init'ing tk

A

Aamer Akhter

Hello,

I'm using the tcltklib extension in ruby 1.8. It seems to be working
well for my transition from tcl. There are a couple of stumbling
blocks I'm running into:

1) is there a way to _not_ start tk? When I create a new interpreter
(let's say from a non X-fwded ssh session) it may cause a failure. I'm
only interested in Tcl.

2) Is there a japanese to english translation of
ext/tcltklib/MANUAL.euc? Or can somebody point to a tool that I may
use to do the translation? babelfish.altavista does not appear to
work.

3). Are there any examples of ruby methods being called from the tcl
code running inside the interpreter?

Thank-you,

Aamer Akhter,
cisco Systems
 
B

Brett H. Williams

Hello,

I'm using the tcltklib extension in ruby 1.8. It seems to be working
well for my transition from tcl. There are a couple of stumbling
blocks I'm running into:

1) is there a way to _not_ start tk? When I create a new interpreter
(let's say from a non X-fwded ssh session) it may cause a failure. I'm
only interested in Tcl.

This is a big pain for me as well. I would really like to have this fixed,
as Ruby/Tcl interaction is important to me. But it hasn't been a big
enough pain to try and hack around in the C code :) (yet)
2) Is there a japanese to english translation of
ext/tcltklib/MANUAL.euc? Or can somebody point to a tool that I may
use to do the translation? babelfish.altavista does not appear to
work.

I've done all of my work without any kind of documentation in English.
There just doesn't seem to be that strong an interest in mixing Ruby and
Tcl (we are some of the exceptions). The tcltklib extension was written
for Ruby/Tk. Access to the Tcl interpreter through it is a side effect--a
highly useful side effect for me and you, but nevertheless not really
what was intended by the developers. So using the Tcl interpreter from
Ruby, and vice versa, is probably not even well documented in Japanese
(someone please correct me if I am wrong).
3). Are there any examples of ruby methods being called from the tcl
code running inside the interpreter?

This is how I do it:

set somevar [ruby "some_method()"]

You can put any ruby code as the argument to the 'ruby' proc. You _must_,
however, make sure that the return value of the ruby code is a string, or
things will crash.

You likely will have to do some creative things to get the scope that you
want--Tcl can only communicate directly with class or global variables.
This means if you call out to Tcl from Ruby, you will not have access to
instance or local variables. It makes perfect sense, but typically
requires doing some non-rubyish things to get access to what you need in
Tcl.
 
F

Ferenc Engard

Brett H. Williams said:
On Oct 1, Aamer Akhter wrote: [...]
2) Is there a japanese to english translation of
ext/tcltklib/MANUAL.euc? Or can somebody point to a tool that I may
use to do the translation? babelfish.altavista does not appear to
work.

I have some hungarian notes about its work... :)) Sorry. :-/
for Ruby/Tk. Access to the Tcl interpreter through it is a side effect--a
highly useful side effect for me and you, but nevertheless not really

And me :)

You can register ruby proc objects into tcl and use it. However, it is a
bit though to understand.

Actually, there is a ruby_fmt proc which is buggy, but it is extensively
used by tcltklib. Here is a patch for 1.6.7, but I do not think that it
has changed since then...

--------------------------------------------------------------------
--- tcltk.old.rb 2002-02-07 02:53:30.000000000 +0100
+++ tcltk_jav.rb 2003-01-07 02:36:04.000000000 +0100
@@ -93,9 +93,9 @@
# ruby_fmt command format arguments by `format' and call `ruby'
command
# (notice ruby command receives only one argument)
if $DEBUG
- @ip._eval("proc ruby_fmt {fmt args} { puts \"ruby_fmt: $fmt
$args\" ; ruby [format $fmt $args] }")
+ @ip._eval("proc ruby_fmt {fmt args} { puts \"ruby_fmt: $fmt
$args\" ; set cmd [list ruby [format $fmt $args]] ; uplevel $cmd }")
else
- @ip._eval("proc ruby_fmt {fmt args} { ruby [format $fmt $args]
}")
+ @ip._eval("proc ruby_fmt {fmt args} { set cmd [list ruby [format
$fmt $args]] ; uplevel $cmd }")
end

# @ip._get_eval_string(*args): generate string to evaluate in tcl
interpreter
--------------------------------------------------------------------

Here I post a testprog of mine, ask if you cannot figure out what is
going on...

--------------------------------------------------------------------
require "tcltk"

$DEBUG=1

ip=TclTkInterpreter.new
pr=proc { |*args|
puts "args: #{args}"
puts "valami"
}
# megoldás paraméterátadásra
# cb.to_eval: {ruby_fmt {TclTk._callcallback("c_1", "%%s")} %s}
cb=TclTkCallback.new(ip,pr,"%s")
puts "cb to_eval: #{cb.to_eval}"

# a [format] a %%s helyére %s-t, %s helyére pedig param1-et helyettesít,
azaz:
# ... -command {ruby_fmt {TclTk._callcallback("c_1", "%s")} param1}
btn1=TclTkWidget.new(ip,".","button","-text valami","-command [format ",
cb,"param1]")
ip.pack(btn1)

TclTk.mainloop
--------------------------------------------------------------------
 
B

Brett H. Williams

Nice to see a fellow industry member dealing with the same problem ;-)



I'm more than willing to spend some time on this. But I'm new to ruby, and
to the tcl-C portions.

It seems like the thing to do is be able to pass the desire for no tk in via
the new call:

TclTkIp.new(notk => 1),

It looks like tcltklib.c:ip_init() gets called. The current parameters wind
up being plugged into Tcl's argv0 and args. So, in keeping with the current
implementation perhaps something like:

TclTkIp.new($argv0, $args, 1) would be "better"

Where 1 represents the non-desire to load Tk.

One would need to skip over when 1 is set.:

/* from Tcl_AppInit() */
DUMP1("Tk_Init");
if (Tk_Init(ptr->ip) == TCL_ERROR) {
rb_raise(rb_eRuntimeError, "%s", ptr->ip->result);
}
DUMP1("Tcl_StaticPackage(\"Tk\")");
#if TCL_MAJOR_VERSION >= 8
Tcl_StaticPackage(ptr->ip, "Tk", Tk_Init, Tk_SafeInit);
#else
Tcl_StaticPackage(ptr->ip, "Tk", Tk_Init,
(Tcl_PackageInitProc *) NULL);
#endif

This kind of approach has merit... however, in the current setup, simply
doing:

require 'tk'

dies if the DISPLAY is not set. It seems a reorganization of how the
tcltklib module is presented would be needed as well.

Am I missing a better way to get access to the Tcl interpreter?
;-) yeah. I already ran into that. I've been using the ruby_fmt proc that
tcltk creates on init. That's just a wrapper for calling the ruby tcl
command.

I have not been using this, but perhaps I should. The way I've been doing
it usually leads to naming differences and confusion, like:

TclFuncs = <<-EOTCL
proc foo {args} {
ruby {bar('$args')}
}
EOTCL

#TclFuncs is evaled into the tcl interpreter...

def bar(args)
...
end

I don't think the importance of the above has sunk in yet. Do you mean to
say that in a class, I won't be able to do something like:

Ip._eval("puts #{var}")

No, because #{var} will be interpolated before the call to Tcl's eval.

What I mean is that the following will not work (note that TclUtils
provides some wrapper functionality that ultimately results in a call to
Tk.tk_call("eval", cmd)... I didn't know about _eval which is probably what
I should be using):

#tcl function defined as follows...
proc some_proc {} {
set somevar [ruby {do_something()}]
}

#and a ruby methods defined as...
class SomeClass
def do_something()
...
return some_str
end

def some_instance_method()
TclUtils.eval("some_proc")
end
end

When you call some_instance_method(), and it runs the tcl proc 'some_proc',
the Tcl interpreter is calling things at the basest level of Ruby scoping,
so there will be no such method 'do_something' at that level.


If this seemed obvious to you that such a thing wouldn't work, perhaps it
is. But it is an ugliness you have to deal with when spanning the two
worlds.

I end up having a current_obj variable or something which can be gotten at
with a class method at the Tcl level, i.e.:

proc some_proc {} {
set somevar [ruby {SomeClass.current_obj.do_something()}]
}

#and...
class SomeClass
def SomeClass.current_obj
return @@current_obj
end

...

def some_instance_method()
@@current_obj = self
TclUtils.eval("some_proc")
end
end

Ugly. Sinfully ugly. Luckily, I try to keep Ruby in control of most
everything, and the Tcl is a configuration file, so I don't need to do this
that often.
 
F

Ferenc Engard

I end up having a current_obj variable or something which can be gotten at
with a class method at the Tcl level, i.e.:

proc some_proc {} {
set somevar [ruby {SomeClass.current_obj.do_something()}]
}

#and...
class SomeClass
def SomeClass.current_obj
return @@current_obj
end

...

def some_instance_method()
@@current_obj = self
TclUtils.eval("some_proc")
end
end

Ugly. Sinfully ugly. Luckily, I try to keep Ruby in control of most
everything, and the Tcl is a configuration file, so I don't need to do this
that often.

Or you can use the TclTkCallback class as I have shown in my previous
post:

class SomeClass
...
def do_something
...
return some_str
end

def some_instance_method()
pr=proc {do_something}
cb=TclTkCallback.new(ip,pr,"%s")
$interpreter._eval(cb.to_eval) # or something to eval cb.eval in the
tcl interpreter
end
end
 
H

Hidetoshi NAGAI

Hi,

Maybe this reply mail is too late.
# Sorry, but I was out on business trip.

From: (e-mail address removed) (Aamer Akhter)
Subject: tcltklib and not init'ing tk
Date: Wed, 1 Oct 2003 15:20:05 +0900
Message-ID: said:
1) is there a way to _not_ start tk? When I create a new interpreter
(let's say from a non X-fwded ssh session) it may cause a failure. I'm
only interested in Tcl.

from ChangeLog of CVS Head,
----------------------------------------------
Fri Aug 29 17:30:15 2003 Hidetoshi NAGAI <[email protected]>
(snip)
* ext/tcltklib/tcltklib.c : can create a interpreter without Tk
----------------------------------------------
Please create a Tcl interpreter by TclTkIp.new(ip_name, nil).
'ip_name' is the name of the interpreter which is shown with
'winfo interps' and so on.
Usually, 2nd argument of TclTkIp.new method is given command
line options of 'wish' (e.g. TclTkIp.new('FOO', '-geometry
500x200 -use 0x2200009') ). But if given nil or false, the
interpreter starts without Tk.

Unfortunately, tk.rb doesn't work with the interpreter without
initialized Tk library. Therefore you must call TclTkIp#invoke
or TclTkIp#eval. If you want to wrap the control script using
such methods by Ruby's classes or modules, please refer TkCore
or TkComm moduless on tk.rb. They may help you.

BTW, there is a known bug on tcltklib.c. It causes 'Segmentation
Fault' when 'vwait' or 'tkwait' command is called on the other
thread than 'mainloop' thread. Those commands call Tcl_DoOneEvent()
function. And it conflicts with the eventloop control of tcltklib.c.
I've been working on fixing the problem. I think I must implement
the routines to replace 'vwait' and 'tkwait'.
 
A

Aamer Akhter

Hidetoshi NAGAI said:
Hi,

Maybe this reply mail is too late.
# Sorry, but I was out on business trip.

Hidetoshi,

Thank-you for responding. It seems like these changes were in r1.39 of
tcltklib.c, while 1.38 was the version released with with 1.8.0. I
should have checked the CVS.
from ChangeLog of CVS Head,
----------------------------------------------
Fri Aug 29 17:30:15 2003 Hidetoshi NAGAI <[email protected]>
(snip)
* ext/tcltklib/tcltklib.c : can create a interpreter without Tk
----------------------------------------------
Please create a Tcl interpreter by TclTkIp.new(ip_name, nil).
'ip_name' is the name of the interpreter which is shown with
'winfo interps' and so on.
Usually, 2nd argument of TclTkIp.new method is given command
line options of 'wish' (e.g. TclTkIp.new('FOO', '-geometry
500x200 -use 0x2200009') ). But if given nil or false, the
interpreter starts without Tk.

I would suggest not using the argv parameter space for indicating the
non-desire for Tk. One might one to pass command line arguments to
tclsh ( in the same way as to wish)
Unfortunately, tk.rb doesn't work with the interpreter without
initialized Tk library. Therefore you must call TclTkIp#invoke
or TclTkIp#eval. If you want to wrap the control script using
such methods by Ruby's classes or modules, please refer TkCore
or TkComm moduless on tk.rb. They may help you.

BTW, there is a known bug on tcltklib.c. It causes 'Segmentation
Fault' when 'vwait' or 'tkwait' command is called on the other
thread than 'mainloop' thread. Those commands call Tcl_DoOneEvent()
function. And it conflicts with the eventloop control of tcltklib.c.
I've been working on fixing the problem. I think I must implement
the routines to replace 'vwait' and 'tkwait'.

While I'm not an active user of vwait, tkwait and espically not
threads as they're not supported in tcl-expect, I think the TKinter
python library has worked around these type of issues see:

Modules/_tkinter.c in the regular python distribution


I would like to work with yon on improving the transferability of
lists and arrays between tcl and ruby, if you are interisted.
 
H

Hidetoshi NAGAI

Hi,

# I resend the following message, because I had no delivery of it.
# I'm sorry, if you saw it twice.

From: (e-mail address removed) (Aamer Akhter)
Subject: Re: tcltklib and not init'ing tk
Date: Sun, 5 Oct 2003 06:56:12 +0900
Message-ID: said:
I would suggest not using the argv parameter space for indicating the
non-desire for Tk. One might one to pass command line arguments to
tclsh ( in the same way as to wish)

Hmm... I don't think so. Because, command line options ( except
display options for wish ) can be given by Ruby.
For example, when want to evaluate the following script on Ruby/Tcl,
---<foo.tcl>----------------
puts "argc = $argc"
puts "argv = $argv"
puts "argv0 = $argv0"
----------------------------
the following can simulate 'tclsh foo.tcl 1 2 3'.
----------------------------
require 'tcltklib'
ip = TclTkIp.new('foo.tcl', nil)
ip._eval('set argc 3')
ip._eval('set argv {1 2 3}')
ip._eval('source foo.tcl')
----------------------------
While I'm not an active user of vwait, tkwait and espically not
threads as they're not supported in tcl-expect, I think the TKinter
python library has worked around these type of issues see:
Modules/_tkinter.c in the regular python distribution

If you don't use threads, there is no problem (probably).
The trouble depends on "thread switching".

To avoid confliction of Tk operations between threads, the invoked
command on the other thread than eventloop thread are serialized
by adding into the event queue. And then, the invoking thread sleeps
and waits for evaluation of the command. The event queue handler,
which called on Tcl_DoOneEvent(), evaluates the command, and wakes
the sleeping thread.

Tcl's eventloop is the repeat of calling Tcl_DoOneEvent().
Current Ruby/Tk uses its own eventloop for smooth switching of
threads. But, as I wrote on the last mail, 'vwait' and 'tkwait'
call Tcl_DoOneEvent() repeatedly. It is equal to situation where
two eventloops are running on each thread. Therefore, the call stack
of Tcl is broken by thread switching.
I would like to work with yon on improving the transferability of
lists and arrays between tcl and ruby, if you are interisted.

Thank you for your proposal. Please tell me what is not enough on
tk.rb (tcltk.rb is not maintained).
 
H

Hidetoshi NAGAI

Hi,

From: Hidetoshi NAGAI <[email protected]>
Subject: Re: tcltklib and not init'ing tk
Date: Sun, 5 Oct 2003 01:55:50 +0900
Message-ID: said:
BTW, there is a known bug on tcltklib.c. It causes 'Segmentation
Fault' when 'vwait' or 'tkwait' command is called on the other
thread than 'mainloop' thread. Those commands call Tcl_DoOneEvent()
function. And it conflicts with the eventloop control of tcltklib.c.
I've been working on fixing the problem. I think I must implement
the routines to replace 'vwait' and 'tkwait'.

I implemented them on the CVS. If you are interested in them,
please try them.
-----<ChangeLog>----------------------------
Wed Oct 15 00:20:15 2003 Hidetoshi NAGAI <[email protected]>

* ext/tcltklib/tcltklib.c: replace Tcl/Tk's vwait and tkwait to
switch on threads smoothly and avoid seg-fault.

* ext/tcltklib/tcltklib.c: add TclTkIp._thread_vwait and
_thread_tkwait for waiting on a thread. (Because Tcl/Tk's vwait
and tkwait command wait on an eventloop.)

* ext/tk/lib/multi-tk.rb: support TclTkIp._thread_vwait and
_thread_tkwait.

* ext/tk/lib/tk.rb: now, TkVariable#wait has 2 arguments.
If 1st argument is true, waits on a thread. If false, waits on
an eventloop. If 2nd argument is true, checks existence of
rootwidgets. If false, doesn't. Default is wait(true, false).

* ext/tk/lib/tk.rb: add TkVariable#tkwait(arg) which is equal to
TkVariable#wait(arg, true). wait_visibility and wait_destroy
have an argument for waiting on a thread or an eventloop.

* ext/tk/lib/tk.rb: improve of accessing Tcl/Tk's special variables.

* ext/tk/lib/tkafter.rb: support 'wait on a thread' and 'wait on
an eventloop'.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

tcltklib 1
tcltklib 1
problem with tk, no tcltklib 2
tcltklib and pthread 1
fedora core 5 and tcltklib 0
Problems getting Tk running 8
Compiling tcltklib 0
Can't find tcltklib 1

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top