From: schendr@drssparc.eptd.Texaco.COM (Dan R. Schenck)
Subject: Problem Losing Expose Events
Followup-To: Ensuring That Windows Get Fully Painted
Organization: Texaco EPTD - Data Management
Date: Fri, 18 Dec 1992 14:57:49 GMT

To ensure that a window gets painted before going on to other things, John 
Ousterhout writes:

  The bottom line is that you have to explicitly wait until you *know* that
  the window has been displayed.  The way to do this is with the tkwait command.
  Set up a binding for <Expose> on the window you want to see, with the
  binding set to modify a particular variable.  Then use tkwait to wait for
  the variable to change to the given value.  Once you know the window's up,
  then you can go off and do your other work.  Be sure to do one more update
  so that the window gets displayed, and also be sure to remove the binding
  when you're done.  Sorry this is so complicated... there should probably
  be a procedure in the Tk script library to do this automatically.

Trying to follow that advice, I implemented the following test:
----------------------------------------------------------------------------------
#!/home/schendr/tcl/bin/pish -f

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 }} {
  set winDone {0}
  set w [genName .InfoMessage]
  toplevel $w
  bind $w <Expose> { 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 [clength $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
  update
  tkwait variable 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 }

----------------------------------------------------------------------------------

The result on a Sun SPARCStation 2 running X11R4/Motif was that the proc
timedMsg never returned to the caller.  When the Quit button is pushed on the
main window the window is destroyed, but the program hangs and has to be killed
at the system level.  It is as if the Expose event is being lost or the 
variable change is taking place before the tkwait is executed.

The above technique works *most* of the time when using Open Windows 2/vtwm, but
not always.

The only sure way around this was to grab the window created by timedMsg, have
timedMsg return its window name to the caller and let the caller do a tkwait
window on the timedMsg window.


I'm using Tk 2.3 with tclX6.4c.

-- 
+--------------- Dan R. Schenck - Data Management - TEXACO EPTD ---------------+
|  External Email:  schendr@Texaco.COM        Texaco Email:  schendr@texhrc    |
|    _   __         Voice:    (713) 954-6053  Fax:  (713) 954-6911  	       |
|   /_) /-/ /\/     US Mail:  Texaco, Inc., 3901 Briarpark, Houston, TX 77042  |
+------------------------------------------------------------------------------+
Newsgroups: comp.lang.tcl