GTKWave -S Tcl script: `after` callbacks never fire; use -R repscript for timed GUI steps
Scripting a timed GTKWave session (open dump, add signals, zoom, pan, quit) for a viewer benchmark: a -S script.tcl runs once after the dump loads, but Tcl after 6000 { gtkwave::/File/Quit } inside it never ran. GTKWave 3.3.121 (conda-forge) stayed open until an outer timeout 90 killed it (exit 124). Without Tk/--wish nothing services the Tcl event loop.
What to use instead (from the man page): -R,--repscript <file> runs a Tcl script periodically from GTK's own timer, and -P,--repperiod <ms> sets the period (default 500). Put a small state machine in it: set ::t0 on the first tick, compute elapsed ms, and do one step per tick when its due time passes (gtkwave::/Time/Zoom/Zoom_Full, gtkwave::setZoomRangeTimes a b, gtkwave::setWindowStartTime t, gtkwave::setMarker t, finally gtkwave::/File/Quit). GTK redraws between ticks, so screen recordings show each step. Keep the one-off setup (gtkwave::addSignalsFromList, gtkwave::getMaxTime) in the -S script. Write marks with clock milliseconds to a file; marks taken inside the -S script only time the Tcl calls, not the redraw, so read draw times off the video frames.
Also seen: with FST input, GTKWave reached the -S script about 1.7 s after launch on an 86k-fac file (it loads the hierarchy up front and signal data on demand).
Correction from the GTKWave 3.3.116 source (tcl_helper.c, repscript_timer): the -R timer returns FALSE and is never rescheduled if it fires while another Tcl script is running (GLOBALS->tcl_running). With -S plus -R together, the first repscript tick can land while the -S script runs, and after that the repscript never runs again (seen: one tick, then nothing for 90 s). Do the one-off setup (addSignalsFromList etc.) inside the repscript on its first tick and do not pass -S. The timer also skips its very first tick on purpose.
Second gotcha: the repscript can start before the dump has finished loading. On the first ticks gtkwave::getMaxTime returned 0 (getMinTime -1) and addSignalsFromList added 0 signals with no error. Guard the setup with: if {[gtkwave::getMaxTime] <= 0} { return } at the top of the repscript, and start your step clock only after that passes. With that guard plus no -S, a 7-step script (add rows, zoom full, zoom range, two pans, jump to end, zoom full, /File/Quit) ran to the end and exited 0.