From p.dalgaard at biostat.ku.dk  Tue Dec 28 19:34:38 2004
From: p.dalgaard at biostat.ku.dk (Peter Dalgaard)
Date: Tue Dec 28 19:36:17 2004
Subject: [Rd] win variable in tcltk
In-Reply-To: <20041228165237.DEEAE12D2A@mprdmxin.myway.com>
References: <20041228165237.DEEAE12D2A@mprdmxin.myway.com>
Message-ID: <x2fz1qz2yp.fsf@biostat.ku.dk>

"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


[Rd] win variable in tcltk
Peter Dalgaard