diff --git a/direct/src/showbase/DirectObject.py b/direct/src/showbase/DirectObject.py index 124d7e1f12..1e84518ec5 100644 --- a/direct/src/showbase/DirectObject.py +++ b/direct/src/showbase/DirectObject.py @@ -1,6 +1,7 @@ from MessengerGlobal import * from DirectNotifyGlobal import * +from PythonUtil import * class DirectObject: """ @@ -8,24 +9,56 @@ class DirectObject: """ #def __del__(self): # print "Destructing: ", self.__class__.__name__ - + # Event Handling + def __initEvents(self): + # this function exists because: + # - DirectObject does not have a constructor, and adding one + # would involve touching many, many files + # - a constructor that creates self.events would cause every + # DirectObject to incur the cost of an additional function + # call and dictionary creation + # - DirectObjects that do not use the messenger should not have + # an unused dictionary taking up space + # - the speed hit of calling this function on calls to accept, + # ignore, etc. is negligible, since they are not called often + try: + self.events + except: + # list of events that this object is accepting + # we use a dictionary to avoid linear searches + self.events = {} + def accept(self, event, method, extraArgs=[]): + self.__initEvents() + ifAbsentPut(self.events, event, None) messenger.accept(event, self, method, extraArgs, 1) def acceptOnce(self, event, method, extraArgs=[]): + self.__initEvents() + ifAbsentPut(self.events, event, None) messenger.accept(event, self, method, extraArgs, 0) + def _INTERNAL_acceptOnceExpired(self, event): + """ this should only be called by the messenger """ + if self.events.has_key(event): + del self.events[event] + def ignore(self, event): + self.__initEvents() + if self.events.has_key(event): + del self.events[event] messenger.ignore(event, self) def ignoreAll(self): - messenger.ignoreAll(self) + self.__initEvents() + for event in self.events.keys(): + messenger.ignore(event, self) + self.events.clear() def isAccepting(self, event): - return messenger.isAccepting(event, self) + self.__initEvents() + return self.events.has_key(event) def isIgnoring(self, event): - return messenger.isIgnoring(event, self) - - + return not self.isAccepting(event) diff --git a/direct/src/showbase/Messenger.py b/direct/src/showbase/Messenger.py index 21877db232..3e4b0e1090 100644 --- a/direct/src/showbase/Messenger.py +++ b/direct/src/showbase/Messenger.py @@ -65,22 +65,23 @@ class Messenger: if (len(acceptorDict) == 0): del self.dict[event] - def ignoreAll(self, object): - """ ignoreAll(self, DirectObject) - Make this object no longer respond to any events it was accepting - Useful for cleanup - """ - if Messenger.notify.getDebug(): - Messenger.notify.debug(`object` + '\n now ignoring all events') - for event, acceptorDict in self.dict.items(): - # If this object is there, delete it from the dictionary - if acceptorDict.has_key(object): - del acceptorDict[object] - # If this dictionary is now empty, remove the event - # entry from the Messenger alltogether - if (len(acceptorDict) == 0): - del self.dict[event] - +## ### moved into DirectObject for speed +## ### +## def ignoreAll(self, object): +## """ ignoreAll(self, DirectObject) +## Make this object no longer respond to any events it was accepting +## Useful for cleanup +## """ +## if Messenger.notify.getDebug(): +## Messenger.notify.debug(`object` + '\n now ignoring all events') +## for event, acceptorDict in self.dict.items(): +## # If this object is there, delete it from the dictionary +## if acceptorDict.has_key(object): +## del acceptorDict[object] +## # If this dictionary is now empty, remove the event +## # entry from the Messenger alltogether +## if (len(acceptorDict) == 0): +## del self.dict[event] def isAccepting(self, event, object): """ isAccepting(self, string, DirectOject) @@ -120,19 +121,26 @@ class Messenger: # We have to make this apparently redundant check, because # it is possible that one object removes its own hooks # in response to a handler called by a previous object. - callList = acceptorDict.get(object) - if callList: - method, extraArgs, persistent = callList + # + # NOTE: there is no danger of skipping over objects due to + # modifications to acceptorDict, since the for..in above + # iterates over a list of objects that is created once at + # the start + callInfo = acceptorDict.get(object) + if callInfo: + method, extraArgs, persistent = callInfo apply(method, (extraArgs + sentArgs)) # If this object was only accepting this event once, # remove it from the dictionary if not persistent: + # notify the object that the event has been triggered + object._INTERNAL_acceptOnceExpired(event) # We need to check this because the apply above might # have done an ignore. if acceptorDict.has_key(object): del acceptorDict[object] - # If the dictionary at this event is now empty, remove the event - # entry from the Messenger alltogether + # If the dictionary at this event is now empty, remove + # the event entry from the Messenger altogether if (self.dict.has_key(event) and (len(self.dict[event]) == 0)): del self.dict[event] @@ -170,7 +178,7 @@ class Messenger: params[0] = newMethod # Found it retrun true retFlag += 1 - # didnt find that method, return false + # didn't find that method, return false return retFlag def toggleVerbose(self):