Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

why does this (windows) "tail" program not respond to the mouse?

1 view
Skip to first unread message

google...@rocketship1.biz

unread,
Jul 18, 2008, 3:31:51 PM7/18/08
to
The following is a small program which
should implement something like the unix
tail functionality. However, when running
this (on windows) as soon as I simply
place my mouse pointer over the console
output window (that this program opens) I
get a busy cursor and the program will
not respond to the mouse. If something
overlaps the console window and then
exposes it, the windows is not redrawn.

It will wake up when the channel is closed. But the
window cannot be moved, even though there
are a liberal amount of update calls
being made during each call to wait. Also, the
output text does not show up until the
channel is closed (when the parent exits). The
variable n tells me that it did actually loop a
number of times.

This is a 8.5.2 windows tcklit.exe on win2000.


I am invoking it as follows, from this 2 line program.


set ::console [open "|tclkit-win32.upx.exe {tail.tcl} &" w]
puts $::console "hello from the main" ; flush $::console


Here's the tail.tcl program,
# --------------------------------------------------
proc wait {time} {
for {set n 0} {$n < 5} {incr n} {
after [expr ( int($time / 5) )]
update
}
}
console show
console eval {wm geom . 120x7+50+600}
update

wm wi .
fconfigure stdin -blocking 0
puts "starting....";update
set n 0
while { true } {
incr n
set out [gets stdin data]
if { [eof stdin] } {
puts "eof seen" ; update
break
}
if { $out < 0 } {
wait 250
continue
}
puts " $n) $data" ; update
}
puts "done..." ;update
wait 10000
exit

Bryan Oakley

unread,
Jul 18, 2008, 7:44:39 PM7/18/08
to
google...@rocketship1.biz wrote:
> Here's the tail.tcl program,
> # --------------------------------------------------
> proc wait {time} {
> for {set n 0} {$n < 5} {incr n} {
> after [expr ( int($time / 5) )]

Are you aware that "after <number>" sleeps for that number of
milliseconds without processing events, during which your program will
freeze? In other words, your app freezes because you are telling it to.

Also, since you are running an event loop there's no reason to have your
own infinite loop -- the event loop is, after all, an infinite loop.
Another good rule of thumb is, never call update. Unless you fully
understand the implications it's best to avoid the tempation.

If you want a procedure to be called every N milliseconds, simply create
a job and reschedule it at the appropriate interval, letting the event
loop do the work:

proc readData {delay} {

<do whatever processing you want>

# reschedule this procedure after $delay ms unless
# some terminal condition is met
if {! <some condition>} {
after $delay [list readData $delay]
}
}
# run the first iteration
readData 250


No doubt others will advocate using [info level] rather than hard-coding
what gets executed. It's a perfectly fine solution, but I think this
more clearly illustrates what is happening.

Finally, search for "tail" on the tcler's wiki. There are many examples.

David Gravereaux

unread,
Jul 18, 2008, 10:55:49 PM7/18/08
to
Bryan Oakley wrote:
> the event loop is, after all, an infinite loop.

I'm placing you in my quote file. Well said :)

google...@rocketship1.biz

unread,
Jul 19, 2008, 5:15:12 PM7/19/08
to
On Jul 18, 4:44 pm, Bryan Oakley <oak...@bardo.clearlight.com> wrote:

Well, something else is going on here then. Here's the new version,
same
problem, no update calls, written as suggested.

(BTW, my wait proc in the original breaks up the call to wait
into 5 smaller waits, each of 50 ms, with an update call - this
should have worked as far as I can tell)

In this new case, as soon as I launch this, I get 2 windows, one is
simply
the empty toplevel that the the main program creates when called by
tclkit
and no widgets are created. The second is the console window created
by
the exec'd tail.tcl program.

AFter the 2 windows appear, if I click in the console window first, it
works, but if I click on the main's toplevel window, the console
window
again becomes busy and hangs. If I put another puts inside the proc,
it
will spit out a line each time the timer goes off, but the console
window
is still frozen.

Alternatively, if I create a simple exit button, like so, the
behavior is slightly different.

Now, if I just launch this, and don't move the mouse over the console
windows, it will spit out the "out = # now waiting", and # is
increasing each time. As soon as the mouse is simply moved over
the console window (no button clicking), then the window freezes,
the cursor becomes the busy (sand timer) cursor, and the output stops.
The console window is still unselected, but is now frozen. Clicking on
the exit button in the main program causes the console window to say
it say the eof and then it exits in 1 second later.


# -------------------------------------------------------------
pack [button .b -text exit -command exit]


set ::console [open "|tclkit-win32.upx.exe {tail.tcl} &" w]
puts $::console "hello from the main"
flush $::console

# ---------------------------------------------


console show
console eval {wm geom . 120x7+50+600}

wm wi .
fconfigure stdin -blocking 0
puts "starting...."

set num 0
proc readData {delay} {
global num
incr num


set out [gets stdin data]
if { [eof stdin] } {

puts "$num eof seen"
after 2000 exit
return
}
if { $out < 0 } {
puts "out = $num now waiting"
after $delay {readData 250}
return
}
puts "$num) $data"
after $delay {readData 250}
}
readData 250

Ralf Fassel

unread,
Jul 21, 2008, 5:42:54 AM7/21/08
to
* Bryan Oakley <oak...@bardo.clearlight.com>

| If you want a procedure to be called every N milliseconds, simply
| create a job and reschedule it at the appropriate interval, letting
| the event loop do the work:
|
| proc readData {delay} {
|
| <do whatever processing you want>
|
| # reschedule this procedure after $delay ms unless
| # some terminal condition is met
| if {! <some condition>} {
| after $delay [list readData $delay]
| }
| }

If the proc needs to definitely re-run after the delay, it might be
preferable to reschedule first, then do the work. This way, an error
while doing the work does not cause the schedule to stop. Of course
if the repeat-interval is short and the error is repeating, you get
tons of error windows in wish :-).

set ::after_id {}
proc readData {delay} {
after cancel $::after_id
set ::after_id [after $delay [list readData $delay]]



<do whatever processing you want>
}

readData ...

YMMV.
R'

google...@rocketship1.biz

unread,
Jul 21, 2008, 2:04:46 PM7/21/08
to

I don't see what difference this would make to
the problem I am seeing. My goal is not to implement
a "tail" program that reacts instantly, I just need
to be able to write to this stream from one process
and see the output in the other. Actually, I was looking
for a solution to the problem of puts from a thread not
working on windows, like it does on *nix systems.

This tail program is really just the aspect of the
unix tail that would let you write to a file from
one process and display the results as they were
output in another windows using tail -f. In fact, I
began this with files, but then hit on the pipeline
idea.

What I can't figure is how the existence of the
exit button in one process affects the other
process at all. That is strange and seems to
indicate some sort of focus problem - maybe
a bug. I'm curious if anyone else can even
reproduce this behavior with the above
code.

Note, the above describes 2 programs, with the
4 lines between the two comment #---- lines
being the first, and the second section is
the "tail" program.

Ralf Fassel

unread,
Jul 21, 2008, 2:20:06 PM7/21/08
to
* google...@rocketship1.biz

| > If the proc needs to definitely re-run after the delay, it might be
| > preferable to reschedule first, then do the work.
--<snip-snip>--

| I don't see what difference this would make to
| the problem I am seeing.

None. Sorry, I should probably have adjusted the 'Subject' line,
since my reply was targeted at a completely different aspect in Bryans
reply (Message-ID: <yV9gk.30548$co7....@nlpi066.nbdc.sbc.com>).

Did you see that reply by Bryan Oakley? It points out some problems
with your code which seem to be crucial to the answer to your original
question.

R'

google...@rocketship1.biz

unread,
Jul 22, 2008, 10:33:56 PM7/22/08
to
On Jul 21, 11:20 am, Ralf Fassel <ralf...@gmx.de> wrote:
> * googlegro...@rocketship1.biz

> | > If the proc needs to definitely re-run after the delay, it might be
> | > preferable to reschedule first, then do the work.
> --<snip-snip>--
> | I don't see what difference this would make to
> | the problem I am seeing.
>
> None. Sorry, I should probably have adjusted the 'Subject' line,
> since my reply was targeted at a completely different aspect in Bryans
> reply (Message-ID: <yV9gk.30548$co7.21...@nlpi066.nbdc.sbc.com>).

>
> Did you see that reply by Bryan Oakley? It points out some problems
> with your code which seem to be crucial to the answer to your original
> question.
>
> R'

Yes, I saw his reply, and I tried to implement the code just as he
had suggested, which I posted. Unfortunately, his suggestion, while
useful as technique for avoiding update calls, didn't resolve the
issue I have. Since I can't see what the problem is, I can't use
this technique to provide a debug output console for threads. I'm
at the point where I was going to write something using a text widget
in case the problem is in the console code. But I'm afraid
I'll just come up against the same bug (I now believe this
is a bug in tcl/tk).

Thanks


Ralf Fassel

unread,
Jul 23, 2008, 5:30:52 AM7/23/08
to
* google...@rocketship1.biz

| Yes, I saw his reply, and I tried to implement the code just as he
| had suggested, which I posted. Unfortunately, his suggestion, while
| useful as technique for avoiding update calls, didn't resolve the
| issue I have. Since I can't see what the problem is, I can't use
| this technique to provide a debug output console for threads.

I have to admit that I do not know much about tclcon on windows, and
the differences of TclCon (or Tkcon?) to plain TCL/Tk, so take the
following with a grain of salt.

The code you posted in
Message-ID: <31c36f47-9447-47cd...@v26g2000prm.googlegroups.com>
starts with


set ::console [open "|tclkit-win32.upx.exe {tail.tcl} &" w]

That sounds strange to my TCL-ears. Why use the '&' sign in there if
opening a pipe? Usually I would have expected

# redirect stderr to see debugging messages
set ::console [open "|tclkit-win32.upx.exe tail.tcl 2>@stderr" w]

And in tail.tcl just set up a fileevent for stdin, and let the
callback handle the input:

proc handle_stdin {} {
set count [gets stdin data]
if { [eof stdin] } {
puts stderr "eof seen on stdin, exiting"
close stdin
exit 0
}
if { $count > 0 } {
puts stderr "READ from stdin {$data}"
}
}
fconfigure stdin -blocking 0
fileevent stdin readable handle_stdin
# The following vwait is only necessary in a tclsh which has no
# event loop by itself (eg. wish already has an event loop running)
vwait forever

HTH
R'

google...@rocketship1.biz

unread,
Jul 23, 2008, 3:16:22 PM7/23/08
to
On Jul 23, 2:30 am, Ralf Fassel <ralf...@gmx.de> wrote:

> The code you posted in

> Message-ID: <31c36f47-9447-47cd-b6b2-294f7581d...@v26g2000prm.googlegroups.com>


> starts with
> set ::console [open "|tclkit-win32.upx.exe {tail.tcl} &" w]
>
> That sounds strange to my TCL-ears. Why use the '&' sign in there if
> opening a pipe? Usually I would have expected
>
> # redirect stderr to see debugging messages
> set ::console [open "|tclkit-win32.upx.exe tail.tcl 2>@stderr" w]
>

I used the & because I read that when using the pipe symbol | in
the open statement, that what follows is the same as when using
exec. And I use & with exec so it does not wait until the
exec'd process exits.

Anyway, I tried your suggestion, and I get an error. It says
channel "console2" wasn't opened for writing, so I'm not sure
what tcl thinks I'm doing nor do I understand what's going on
here either. I have no console2 anywhere, so I'm guessing it's
some syntax issue with the ::console and the 2 in the redirection
that is getting messed up.

Next, I tried your suggestion, still using my original
open statement, with the following code, with no change
in behavior. (But the code keeps getting smaller :)

package require Tk ;# just a guess


console show
console eval {wm geom . 120x7+50+600}

wm wi .


fconfigure stdin -blocking 0
puts "starting...."


set num 0
proc handle_stdin {} {
global num
incr num


set count [gets stdin data]
if { [eof stdin] } {

puts "eof seen on stdin, exiting"
fileevent stdin readable {} ;# remove handler
close stdin
after 16000 {exit 0} ;# delay exit so this is visible
}
if { $count > 0 } {
puts "$num) $data"
}
}
fileevent stdin readable handle_stdin
vwait forever

Ralf Fassel

unread,
Jul 24, 2008, 9:36:36 AM7/24/08
to
* google...@rocketship1.biz

| I used the & because I read that when using the pipe symbol | in the
| open statement, that what follows is the same as when using
| exec. And I use & with exec so it does not wait until the exec'd
| process exits.

Ok, this sounds like a minor flaw in the 'open' documentation. With
'exec' you need the "&", otherwise your app is blocked until the
exec'd program finishes. With 'open', you don't need the "&" because
your program is not blocked here. The side-effect of using an "&" is
to redirect stdout and stderr of the application (which actually might
be what you want). I'm not sure whether this side-effect is
intentional in the case of 'open', though.

set ::console [open "|tclkit-win32.upx.exe tail.tcl &" w]

would then be the same as
set ::console [open "|tclkit-win32.upx.exe tail.tcl >@stdout 2>@stderr" w]

| Anyway, I tried your suggestion, and I get an error. It says
| channel "console2" wasn't opened for writing, so I'm not sure
| what tcl thinks I'm doing nor do I understand what's going on
| here either.

That's because omitting the "&" now closed the stdout of the
application and the 'puts' in there failed. So either keep the "&" or
use explicit redirection as shown above.

| [tail.tcl]


| package require Tk ;# just a guess

Good for starting the event loop, you don't need the 'vwait' then.

| console show
| console eval {wm geom . 120x7+50+600}

Not sure about these... Is this the window where the output is shown?

| wm wi .
| fconfigure stdin -blocking 0

| puts "starting...."

This 'puts' may fail if the program was started with a write-only pipe
(see above).

| set num 0
| proc handle_stdin {} {
| global num
| incr num
| set count [gets stdin data]
| if { [eof stdin] } {
| puts "eof seen on stdin, exiting"


| fileevent stdin readable {} ;# remove handler

That's not necessary, 'close' will take care of that.

| close stdin
| after 16000 {exit 0} ;# delay exit so this is visible
| }
| if { $count > 0 } {
| puts "$num) $data"
| }
| }
| fileevent stdin readable handle_stdin


| vwait forever

'vwait' should not be necessary if you 'required' Tk earlier.

If this still does not work, I'm out of ideas. Must be some
interaction with the console, since it works here with tclsh and/or
wish.

HTH
R'

0 new messages