"Gabor Grothendieck" <ggrothendieck@myway.com> writes:
> The following gives an error message:
>
> library(tcltk)
>
> win <- list(env="A")
>
> tt <- tktoplevel()
> but <- tkbutton(tt, text="X",
command=expression(tkdestroy(tt)))
> tkgrid(but)
>
> however, if one comments out the win line (and removes the
> win variable) then it works. It seems that tcltk is making
> use of a variable called win with a component name of env
> and I just happened to have a list in my workspace called win
> in which one of the components was called env. I suggest that
> this either be changed or documented. I spent quite a large
> amount of time until I realized what was going on.
Nice catch, Gabor...
The problem is at the end of .Tcl.args.objv:
current.win <- if (exists("win", envir = parent.frame()))
get("win", envir = parent.frame())
else .TkRoot
which tries to pick up the current window from the enclosing call to
tkwidget(). However, that is the grandparent, not the parent frame, so
we need parent.frame(2), twice, and probably also inherits=FALSE as a
partial safeguard. That will not cure the inadvertent capture though,
since you could run tkcmd() directly in an envir that has a "win"
variable.
The logic is quite dodgy in the first place, and maybe it could do
with a facelift. The basic issue is how to figure out which window a
callback binds to, so that we can save it in its environment and
thereby protect it from the garbage collector. There are three main
cases:
1) widget creation
2) widget configuration
3) explicit bindings
i.e. in Tcl:
button .a.b -command $cmd
.a.b configure -command $cmd
bind .a.b <B-1> $cmd
respectively. What the R code is doing is to pick up from the call the
last window mentioned. In the widget creation case it looks in the
parent environment.
However, the third case can take a "tag" instead of a window name, in
which case it is far from obvious what to do, so we have the stopgap
of .TkRoot.
Longer term, this needs fixes on a higher level; I suspect via the
possibility of creating a new object types in Tcl to represent R
objects (Tcl_RegisterObjType() and all that).
Looking at tkwidget() I do however get the feeling that it might be
possible to get rid of the "win" business altogether, just by using
tkcmd(type, win, ...)
where it is currently using .Tk.ID(win). The final Tcl call should be
the same, and val2obj will set current.win correctly.
--
O__ ---- Peter Dalgaard Blegdamsvej 3
c/ /'_ --- Dept. of Biostatistics 2200 Cph. N
(*) \(*) -- University of Copenhagen Denmark Ph: (+45) 35327918
~~~~~~~~~~ - (p.dalgaard@biostat.ku.dk) FAX: (+45) 35327907