onDisplay - run a script after a window is displayed

bll 2017-6-30 This code creates a one-time binding for a window on a <Configure> event without affecting existing bindings. This could be enhanced to fire when both <Configure> and <Visibility> events have triggered.

Instead of having:

    # wait for the window to display...
    # this will not do much if the window hasn't displayed yet
    # if the window has already displayed, there is a small delay.
    after 100 [list $mywindow yview moveto 1.0] ; # scroll to the end

Use:

    ondisp::onDisplay $mywindow [list $mywindow yview moveto 1.0]
namespace eval ondisp {
  variable vars

  proc _addBindTag { w tag } {
    if { [lsearch -exact [bindtags $w] $tag$w] == -1 } {
      bindtags $w [concat [bindtags $w] $tag$w]
    }
    return $tag$w
  }

  proc _removeBindTag { w tag } {
    set b [bindtags $w]
    set idx [lsearch -exact $b $tag$w]
    set b [lreplace $b $idx $idx]
    bindtags $w $b
  }

  proc onDisplay { w script } {
    variable vars

    set c $vars(ondisp.count)
    set bt [_addBindTag $w ondisp$c]
    bind $bt <Configure> [subst -nobackslashes -nocommands {
        $script
        ondisp::_removeBindTag $w ondisp$c
        bind $bt <Configure> {}
    }]
    incr vars(ondisp.count)
  }

  proc init { } {
    variable vars

    set vars(ondisp.count) 0
  }

  init
}