From: spencer@med.umich.edu (Spencer W. Thomas)
Subject: Re: Problem losing expose events
Date: Mon, 21 Dec 92 16:44:20 EST
Organization: University of Michigan
Distribution: comp

In response to schendr@drssparc.eptd.Texaco.COM (Dan R. Schenck).  I
tried e-mail but it bounced.

You need to make winDone global, and declare it in your timedMsg
routine command (and, with tk3.0 in the <Expose> event command).  The
bound commands get executed at the global level, so they cannot see
variables internal to other procedures.

That said, I don't get the behavior you're observing.  When I push the
"test" button, the window comes up, I get the "Returned from timed
message" line, and then the window goes away.  In fact, it frequently
returns from the timedMessage routine before the window is actually
exposed.  When I click Quit, the program quits.  Since the problem is
based on a race condition, this is not too surprising.

I'm running X11R5, Motif, tk2.3/tclX6.4c.  The really interesting
thing is when I put an "echo winDone" right after the tkwait line.
Without the "global winDone" declaration, this always prints 0.  With
the global declaration, it prints 1.  Something strange is happening
in tkwait.

Under tk3.0, I do get the behavior you're seeing.  Apparently the
tk3.0 update command waits until the window is exposed before
returning, so the tkwait is superfluous.  (I'm not sure about this,
but I always get "About to wait winDone = 1" from the code below under
tk3.0, but not always under tk2.3.) I fixed the "race condition" by
adding an if {$winDone == 0} before the tkwait.

The code below is my modification to your code with a switch variable
on the first line to change the behavior between "broken" and working.


=S

set broken 0

# Define tclX procs if not present. (tk3.0)
if {[string length [info command echo]] == 0 } {
proc echo {args} {
	puts stderr $args;
}
proc max {a b} {
	if {$a > $b} { return $a } { return $b }
}
}

proc genName {{var var}} {
  global nameCount
  if [info exists nameCount($var)] {
    incr nameCount($var)
  } else {
    set nameCount($var) 0
  }
  return "$var$nameCount($var)"
}

proc timedMsg { msg { timeout 30000 }} {
	global broken
	if {! $broken} {global winDone}
  set winDone {0}
# Tk3.0 doesn't allow capitalized window names.
  set w [genName .infoMessage]
  toplevel $w
  bind $w <Expose> { global broken; echo exposed ;if {! $broken} {global winDone};set winDone {1} }
  wm withdraw $w
  wm title $w "Message"

  frame $w.m

  set tmp [split $msg \n]
  set i 0
  foreach line $tmp {
    set i [max $i [string length $line]]
  }

  message $w.m.l -text "$msg" \
    -width [expr $i*9] \
    -relief {raised} \
    -justify {center}
  button $w.m.b -command "destroy $w" -text "OK"

  pack append $w.m $w.m.l top $w.m.b { top pady 5 }
  pack append $w $w.m {top expand fill}
  if { $timeout != "INFINITE" } { after $timeout "removeTimedMsg $w" }

  wm deiconify $w
	echo Before update winDone = $winDone
  update
	echo About to wait winDone = $winDone
  if { $winDone == 0 } { tkwait variable winDone }
  
	echo After wait winDone=$winDone

  return $w

}

proc removeTimedMsg { win } {

  if { [lsearch [winfo children .] $win] > -1 } { destroy $win }

}

frame .f -bg {linen} -relief {raised}
button .f.testbug -text {Launch Msg Win} -bg {cornflowerblue} -fg {white} \
  -command {
    timedMsg "Test of expose bug" 3000
    puts stdout "Returned from timed message"
  }
button .f.quit -text {Quit} -bg {red} -fg {white} -command { destroy . }
pack append .f .f.testbug { top frame center padx 10 pady 10 } \
	       .f.quit { top frame center padx 10 pady 10 }
pack append . .f { top frame center expand fill }
--
=Spencer W. Thomas 		|  Info Tech and Networking, B1911 CFOB, 0704
   "Genome Informatician"	|  Univ of Michigan, Ann Arbor, MI 48109
Spencer.W.Thomas@med.umich.edu	|  313-747-2778, FAX 313-764-4133
Newsgroups: comp.lang.tcl