| 1 | # -*- tcl -*- |
|---|
| 2 | # ### ### ### ######### ######### ######### |
|---|
| 3 | ## UEvent - User Event Service - Tcl-level general Event Handling |
|---|
| 4 | |
|---|
| 5 | # ### ### ### ######### ######### ######### |
|---|
| 6 | ## Requirements |
|---|
| 7 | |
|---|
| 8 | package require Tcl 8.4 |
|---|
| 9 | package require logger |
|---|
| 10 | |
|---|
| 11 | namespace eval ::uevent {} |
|---|
| 12 | |
|---|
| 13 | # ### ### ### ######### ######### ######### |
|---|
| 14 | ## API: bind, unbind, generate |
|---|
| 15 | |
|---|
| 16 | proc ::uevent::bind {tag event command} { |
|---|
| 17 | # Register command (prefix!) as observer for events on the tag. |
|---|
| 18 | # Command will take 3 arguments: tag, event, and dictionary of |
|---|
| 19 | # detail information. Result is token by which the observer can |
|---|
| 20 | # be removed. |
|---|
| 21 | |
|---|
| 22 | variable db |
|---|
| 23 | variable tk |
|---|
| 24 | variable ex |
|---|
| 25 | variable tcounter |
|---|
| 26 | |
|---|
| 27 | log::debug [list bind: $tag $event -> $command] |
|---|
| 28 | |
|---|
| 29 | set tec [list $tag $event $command] |
|---|
| 30 | |
|---|
| 31 | # Same combination as before, same token |
|---|
| 32 | if {[info exists ex($tec)]} { |
|---|
| 33 | log::debug [list known! $ex($tec)] |
|---|
| 34 | return $ex($tec) |
|---|
| 35 | } |
|---|
| 36 | |
|---|
| 37 | # New token, and enter everything ... |
|---|
| 38 | |
|---|
| 39 | set te [list $tag $event] |
|---|
| 40 | set t uev[incr tcounter] |
|---|
| 41 | |
|---|
| 42 | set tk($t) $tec |
|---|
| 43 | set ex($tec) $t |
|---|
| 44 | lappend db($te) $t |
|---|
| 45 | |
|---|
| 46 | log::debug [list new! $t] |
|---|
| 47 | return $t |
|---|
| 48 | } |
|---|
| 49 | |
|---|
| 50 | proc ::uevent::unbind {token} { |
|---|
| 51 | # Removes the event binding represented by the token. |
|---|
| 52 | |
|---|
| 53 | variable db |
|---|
| 54 | variable tk |
|---|
| 55 | variable ex |
|---|
| 56 | |
|---|
| 57 | log::debug [list unbind: $token] |
|---|
| 58 | |
|---|
| 59 | if {![info exists tk($token)]} return |
|---|
| 60 | |
|---|
| 61 | set tec $tk($token) |
|---|
| 62 | set te [lrange $tex 0 1] |
|---|
| 63 | |
|---|
| 64 | log::debug [linsert [linsert $tec 0 =] end-1 ->] |
|---|
| 65 | |
|---|
| 66 | unset ex($tec) |
|---|
| 67 | unset tk($token) |
|---|
| 68 | |
|---|
| 69 | set pos [lsearch -exact $db($te) $token] |
|---|
| 70 | if {$pos < 0} return |
|---|
| 71 | |
|---|
| 72 | if {[llength $db($te)] == 1} { |
|---|
| 73 | # Last observer for this tag,event combination is gone. |
|---|
| 74 | log::debug [linsert $te 0 last!] |
|---|
| 75 | unset db($te) |
|---|
| 76 | } else { |
|---|
| 77 | # Shrink list of observers |
|---|
| 78 | log::debug [linsert [linsert $te 0 shrink!] end @ $pos] |
|---|
| 79 | set db($te) [lreplace $db($te) $pos $pos] |
|---|
| 80 | } |
|---|
| 81 | return |
|---|
| 82 | } |
|---|
| 83 | |
|---|
| 84 | proc ::uevent::generate {tag event {details {}}} { |
|---|
| 85 | # Generates the event on the tag, with detail information (a |
|---|
| 86 | # dictionary). This notifies all registered observers. The |
|---|
| 87 | # notifications are put into the Tcl event queue via 'after 0' |
|---|
| 88 | # events, decoupling them in time from them issueing code. |
|---|
| 89 | |
|---|
| 90 | variable db |
|---|
| 91 | variable tk |
|---|
| 92 | |
|---|
| 93 | log::debug [list generate: $tag $event $details] |
|---|
| 94 | |
|---|
| 95 | set key [list $tag $event] |
|---|
| 96 | if {![info exists db($key)]} return |
|---|
| 97 | |
|---|
| 98 | foreach t $db($key) { |
|---|
| 99 | set cmd [lindex $tk($t) 2] |
|---|
| 100 | log::debug [list trigger! $t = $cmd] |
|---|
| 101 | after 0 [linsert $cmd end $tag $event $details] |
|---|
| 102 | } |
|---|
| 103 | |
|---|
| 104 | return |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | # ### ### ### ######### ######### ######### |
|---|
| 108 | ## Initialization - Tracing, System state |
|---|
| 109 | |
|---|
| 110 | logger::initNamespace ::uevent |
|---|
| 111 | namespace eval ::uevent { |
|---|
| 112 | |
|---|
| 113 | # Information needed: |
|---|
| 114 | # (1) Per <tag,event> the commands bound to it. |
|---|
| 115 | # (2) Per <tag,event,command> a token representing it. |
|---|
| 116 | # (3) For all <tag,event,command> a quick way to check their existence |
|---|
| 117 | |
|---|
| 118 | # (Ad 1) db : array (list (tag, event) -> list (token)) |
|---|
| 119 | # (Ad 2) tk : array (token -> list (tag, event, command)) |
|---|
| 120 | # (Ad 3) ex : array (list (tag, event, command) -> token) |
|---|
| 121 | |
|---|
| 122 | variable db ; array set db {} |
|---|
| 123 | variable tk ; array set tk {} |
|---|
| 124 | variable ex ; array set ex {} |
|---|
| 125 | |
|---|
| 126 | variable tcounter 0 |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | # ### ### ### ######### ######### ######### |
|---|
| 130 | ## Ready |
|---|
| 131 | |
|---|
| 132 | package provide uevent 0.1.2 |
|---|
| 133 | |
|---|
| 134 | ## |
|---|
| 135 | # ### ### ### ######### ######### ######### |
|---|