/usr/share/ftools/POW/Notifications.tcl is in ftools-pow 5.4+dfsg-1build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | ########################################################################
#
# class: Notifications
#
# purpose: Provide a message distribution center for special events.
# Any number of objects/users can ask to be notified when
# a given event occurs.
#
# usage: To create/access the notification center:
# set newObj [gNotifications]
# or
# set oldObj [gNotifications default]
# where the first example creates a new notification center
# and the later returns pre-existing one of an unknown
# name (or creates a new one if one doesn't already exist).
# In most cases, an application should have only one
# notification object, so either create one and store it in
# a global variable, or always access it through the "default"
# method.
#
# To send a message:
# NotificationObj postMessage object message ?args?
# where "object" is the object to which "message" applies,
# usually the sending object. "message" is a string
# describing the event which has just taken place...
# eg, "graphHasFinishedDrawing". "args" contains extra
# information observers may use.
#
# To register to receive messages:
# NotificationObj addObserver observer cmd object message
# where "observer" is the object (or function name) to be
# called when "message" is posted by (or for) "object". "cmd"
# is either the observing object's method to be used or a
# extra/dummy argument passed to an observing function. An
# observing object needs to implement the method:
# body observer::cmd { object message opts } {...}
# while an observing function implements the procedure:
# proc observer { cmd object message opts } {...}
# where opts is an optional list of additional information
# sent by the object.
#
# To unregister:
# NotificationObj removeObserver observer ?object? ?message?
# where "observer" is the same as before. An observer can
# unregister for all messages or just ones from particular
# objects and messages.
#
#######################################################################
itcl::class Notifications {
constructor {} {}
destructor {}
public {
method addObserver { observer cmd object message }
method removeObserver { observer {object ""} {message ""} }
method postMessage { object message args }
method registerRemote { rNotes } { set remoteNotes $rNotes }
}
private {
variable lookup
variable remoteNotes ""
method locateObserver { observer observerList }
}
}
#######################################################################
#
# gNotifications ?default?
#
# Use this procedure to create/access instances of Notifications in
# the global namespace
#
#######################################################################
proc gNotifications { args } {
if { [llength $args]==1 && [lindex $args 0]=="default" } {
set args ""
set gNote [lindex [itcl::find objects ::* -class Notifications] 0]
if { $gNote != "" } {
return $gNote
}
}
return [uplevel #0 Notifications #auto $args]
}
########################################################################
#
# addObserver cmd object message
#
# Use this method to register an object/procedure as an observer for
# a particular object/message
#
########################################################################
itcl::body Notifications::addObserver { observer cmd object message } {
set object [string trimleft $object :]
if { $cmd=="-" } {
set cmd $message
}
if { $remoteNotes != "" \
&& $object != "" && $object != "*" && [itcl::find object *::$object] != "" \
&& [$object isa DistantObject] && $message != "connectionHasClosed" } {
# Looking for a message not sent by a DO, so pass registration
# to remote Notification center.
$remoteNotes addObserver $observer $cmd $object $message
return
}
if { [info exists lookup($message,$object)] } {
set currentObservers $lookup($message,$object)
if { [locateObserver $observer $currentObservers]==-1 } {
lappend currentObservers [list $observer $cmd]
}
} else {
set currentObservers [list [list $observer $cmd]]
}
set lookup($message,$object) $currentObservers
}
########################################################################
#
# removeObserver observer ?object? ?message?
#
# Use this method to remove an object/procedure from receiving
# certian notifications
#
########################################################################
itcl::body Notifications::removeObserver { observer {object ""} {message ""} } {
set object [string trimleft $object :]
if { $remoteNotes != "" \
&& $object != "" && $object != "*" && [itcl::find object *::$object] != "" \
&& [$object isa DistantObject] && $message != "connectionHasClosed" } {
# Looking for a message not sent by a DO, so pass registration
# to remote Notification center.
$remoteNotes removeObserver $observer $object $message
return
}
if { $object!="" && $message!="" } {
if { ![info exists lookup($message,$object)] } return
set currentObservers $lookup($message,$object)
set idx [locateObserver $observer $currentObservers]
if { $idx == -1 } return
set lookup($message,$object) [lreplace $currentObservers $idx $idx]
} else {
foreach key [array names lookup] {
foreach [list o m] [split $key ","] {}
if { ($object=="" || $object==$o) && \
($message=="" || $message==$m) } {
set currentObservers $lookup($key)
set idx [locateObserver $observer $currentObservers]
if { $idx != -1 } {
set lookup($key) [lreplace $currentObservers $idx $idx]
}
}
}
}
}
########################################################################
#
# postMessage object message
#
# Use this method to send a message to all observers
#
########################################################################
itcl::body Notifications::postMessage { object message args } {
set object [string trimleft $object :]
###########
#
# Build list of ...
#
set allObservers {}
#
# ... observers of fully-resolved object-message, ...
#
if { [info exists lookup($message,$object)] } {
eval lappend allObservers $lookup($message,$object)
}
#
# ... observers of all messages from this object, ...
#
if { [info exists lookup(*,$object)] } {
eval lappend allObservers $lookup(*,$object)
}
#
# ... observers of this message from all objects
#
if { [info exists lookup($message,*)] } {
eval lappend allObservers $lookup($message,*)
}
#
# Now send notifications to each observer
#
foreach observer $allObservers {
foreach [list obs cmd] $observer {}
# DebugStr "... notifying \"$obs\" of $message"
if { [catch {$obs $cmd $object $message $args} res] } {
# DebugStr "*** Notify error: $obs $cmd $object $message"
# DebugStr "$res"
}
}
}
########################################################################
#
# Private methods...
#
itcl::body Notifications::locateObserver { observer observerList } {
set idx 0
foreach oldObserver $observerList {
if { $observer == [lindex $oldObserver 0] } {
return $idx
}
incr idx
}
return -1
}
|