HaO 2019-04-12
The Tk bind command allows to add commands by the syntax:
bind win tag +cmd
There is no buildin way to remove the added command.
(Christian Gollwitzer on clt): The "+cmd" syntax is considered as broken. Bindtags (which are lists) or tcllib uevent should be used instead.
HaO: Nevertheless, I face this issue for important global events like androwish "<<WillEnterBackground>>" command, which is potentially important for a lot of modules in common.
Christian: This is the classic case of "misusing" Tk events - an event which has multiple listeners cannot be cleanly expressed in Tk.
If you have all the modules under your control. Refire the event as a uevent in the main setup:
bind . <<WillEnterBackground>> { uevent::generate AndroidWish GoesDown }
then, in each module, you do:
set myid [uevent::bind AndroidWish GoesDown mymethod]
and when you unload the module
uevent::unbind $myid
We use uevent in aRTist precisely to do this - signalling general events that are not connected to a widget.
And Mike Griffin about bindtags:
You can still use bindtags:
% bindtags . Wish all % bindtags . [linsert [bindtags .] 1 CustomFoo] % bindtags . . CustomFoo Wish all % bind CustomFoo <<WillEnterBackground>> [list ScannerUnregister]
(Output above is on Wish on Windows; default bindtags may be different on AndroWish, or already altered by other libraries, but by using linsert as above you can inject your new bindtag safely regardless)
The command "bind win tag +cmd" does the following:
Pseudocode:
proc BindAdd {w t c} { set ccur [bind $w $t] if {$ccur eq ""} { bind $w $t $c } else { bind $w $t $c $ccur\n$c } }
Here is a proposition to remove my own registration.
# Remove first Cmd from bind pattern. # @return true if removed proc BindRemove {Win Pattern CmdIn} { set CmdCur [bind $Win $Pattern] set Pos 0 while {-1 != [set Pos [string first $CmdIn $CmdCur $Pos]]} { # Check if found string starts at the beginning of after a new-line if { $Pos == 0 || [string index $CmdCur $Pos-1] eq "\n" } { # Check if found string ends at end or before a new-line set PosEnd [expr {$Pos + [string length $CmdIn]}] if { $PosEnd == [string length $CmdCur] || [string index $CmdCur $PosEnd] eq "\n" } { # Binding found if {$Pos != 0} { set CmdNew [string range $CmdCur 0 $Pos-2] } else { set CmdNew "" } if {$PosEnd!= [string length $CmdCur]} { if {$CmdNew ne ""} { append CmdNew \n } append CmdNew [string range $CmdCur $PosEnd+1 end] } bind $Win $Pattern $CmdNew return 1 } } incr Pos } return 0 }
Usage:
proc mymodule::init {} { bind . a +[namespace code MyModuleFunction] } proc mymodule::delete {} { bindRemove . a [namespace code MyModuleFunction] }