From jfox at mcmaster.ca  Mon Nov  3 22:33:34 2008
From: jfox at mcmaster.ca (John Fox)
Date: Mon, 3 Nov 2008 16:33:34 -0500
Subject: [Rd] possible tcltk event loop problem
Message-ID: <008201c93dfb$d336f650$79a4e2f0$@ca>

Dear list members,

Rich Heiberger reported to me last week that the Messages window in the
Rcmdr GUI was freezing -- that is, messages posted to this window didn't
appear -- under Windows and R 2.8.0. I was able to confirm this problem on
three Windows systems, one using Vista and the other two XP. In each case, I
used R 2.8.0 and Rcmdr 1.4-4 (the current version). The problem doesn't
occur with R 2.7.2 and Rcmdr 1.4-4. Nor does it occur on my Mac OS/X and
Ubtuntu Linux systems. In my case, the problem occurred only using Rgui, not
under Rterm. Rich experienced the problem with both Rgui and Rterm. On the
other hand, Erich Neuwirth tells me that the Messages window works fine for
him generally under Windows with R 2.8.0 and Rcmdr 1.4-4, so whatever the
source of the problem, it doesn't always manifest itself. Some detail, and a
kludgy solution appear below.

What's odd is that the Rcmdr has three similar windows -- Script, Output,
and Messages, created by the following code:

For the messages window:

    messagesFrame <- tkframe(.commander)
    putRcmdr("messagesWindow", tktext(messagesFrame, bg="lightgray",
        font=getRcmdr("logFont"), height=3, width=log.width, wrap="none"))
    .messages <- MessagesWindow()
    messagesXscroll <- ttkscrollbar(messagesFrame, orient="horizontal",
        command=function(...) tkxview(.messages, ...))
    messagesYscroll <- ttkscrollbar(messagesFrame,
        command=function(...) tkyview(.messages, ...))
    tkconfigure(.messages, xscrollcommand=function(...)
tkset(messagesXscroll, ...))
    tkconfigure(.messages, yscrollcommand=function(...)
tkset(messagesYscroll, ...))

For the script window (note that "log" is a hold-over from earlier
terminology):

    logFrame <- tkframe(CommanderWindow())
    putRcmdr("logWindow", tktext(logFrame, bg="white",
foreground=getRcmdr("log.text.color"),
        font=getRcmdr("logFont"), height=log.height, width=log.width,
wrap="none", undo=TRUE))
    .log <- LogWindow()
    logXscroll <- ttkscrollbar(logFrame, orient="horizontal",
        command=function(...) tkxview(.log, ...))
    logYscroll <- ttkscrollbar(logFrame,
        command=function(...) tkyview(.log, ...))
    tkconfigure(.log, xscrollcommand=function(...) tkset(logXscroll, ...))
    tkconfigure(.log, yscrollcommand=function(...) tkset(logYscroll, ...))

For the output window:

    outputFrame <- tkframe(.commander)

    putRcmdr("outputWindow", tktext(outputFrame, bg="white",
foreground=getRcmdr("output.text.color"),
        font=getRcmdr("logFont"), height=output.height, width=log.width,
wrap="none", undo=TRUE))
    .output <- OutputWindow()
    outputXscroll <- ttkscrollbar(outputFrame, orient="horizontal",
        command=function(...) tkxview(.output, ...))
    outputYscroll <- ttkscrollbar(outputFrame,
        command=function(...) tkyview(.output, ...))
    tkconfigure(.output, xscrollcommand=function(...) tkset(outputXscroll,
...))
    tkconfigure(.output, yscrollcommand=function(...) tkset(outputYscroll,
...))

Note that the functions MessagesWindow(), LogWindow(), and OutputWindow()
simply return their respective tk windows.

These windows are also similarly placed in the master Rcmdr window (slightly
edited):

    tkgrid(.log, logYscroll, sticky="news", columnspan=2)
    tkgrid(logXscroll)
    tkgrid(logFrame, sticky="news", padx=10, pady=0, columnspan=2)

    tkgrid(.output, outputYscroll, sticky="news", columnspan=2)
    tkgrid(outputXscroll, columnspan=1 + (.log.commands &&
!.console.output))
    tkgrid(outputFrame, sticky="news", padx=10, pady=0, columnspan=2)

    tkgrid(.messages, messagesYscroll, sticky="news", columnspan=2)
    tkgrid(messagesXscroll)
    tkgrid(messagesFrame, sticky="news", padx=10, pady=0, columnspan=2)

I was able successfully to write directly to the script and output windows:

> tkinsert(LogWindow(), "end", "\n testing \n")
<Tcl>  

> tkinsert(OutputWindow(), "end", "\n testing \n")
<Tcl> 

But writing to the message window, though it produced no error, also had no
visible effect:

> tkinsert(MessagesWindow(), "end", "\n testing \n")
<Tcl>

Checking the contents of the Messages window via tkget(MessagesWindow(),
"1.0", "end") revealed, however, that the text should have been there.

Suspecting a timing/event-loop-synchronization issue, I inserted a delay
into the function that sends text to the Messages window; here's a
simplified version of that function:

Message <- function(message, type=c("note", "error", "warning")){
	Sys.sleep(0.01)
	.message <- MessagesWindow() 
	if (!missing(message)) {
		tkinsert(.message, "end", paste("\n", message, "\n")) 
		tkyview.moveto(.message, 1.0) 
	} 
}

The 0.01 second delay is apparently sufficient to fix the problem.

I'm reporting the problem because I suspect that there's some issue with
tcltk in the Windows version of R 2.8.0 (though I didn't see anything in the
CHANGES or NEWS file to suggest this).

Regards,
 John 

------------------------------
John Fox, Professor
Department of Sociology
McMaster University
Hamilton, Ontario, Canada
web: socserv.mcmaster.ca/jfox



[Rd] possible tcltk event loop problem
John Fox