Module eventHandler
[hide private]
[frames] | no frames]

Source Code for Module eventHandler

  1  #eventHandler.py 
  2  #A part of NonVisual Desktop Access (NVDA) 
  3  #This file is covered by the GNU General Public License. 
  4  #See the file COPYING for more details. 
  5  #Copyright (C) 2007-2010 Michael Curran <mick@kulgan.net>, James Teh <jamie@jantrid.net> 
  6   
  7  import queueHandler 
  8  import api 
  9  import speech 
 10  import appModuleHandler 
 11  import treeInterceptorHandler 
 12  import globalVars 
 13  import controlTypes 
 14  from logHandler import log 
 15  import globalPluginHandler 
 16   
 17  #Some dicts to store event counts by name and or obj 
 18  _pendingEventCountsByName={} 
 19  _pendingEventCountsByObj={} 
 20  _pendingEventCountsByNameAndObj={} 
 21   
 22  #: the last object queued for a gainFocus event. Useful for code running outside NVDA's core queue  
 23  lastQueuedFocusObject=None 
 24   
25 -def queueEvent(eventName,obj,**kwargs):
26 """Queues an NVDA event to be executed. 27 @param eventName: the name of the event type (e.g. 'gainFocus', 'nameChange') 28 @type eventName: string 29 """ 30 global lastQueuedFocusObject 31 queueHandler.queueFunction(queueHandler.eventQueue,_queueEventCallback,eventName,obj,kwargs) 32 if eventName=="gainFocus": 33 lastQueuedFocusObject=obj 34 _pendingEventCountsByName[eventName]=_pendingEventCountsByName.get(eventName,0)+1 35 _pendingEventCountsByObj[obj]=_pendingEventCountsByObj.get(obj,0)+1 36 _pendingEventCountsByNameAndObj[(eventName,obj)]=_pendingEventCountsByNameAndObj.get((eventName,obj),0)+1
37
38 -def _queueEventCallback(eventName,obj,kwargs):
39 curCount=_pendingEventCountsByName.get(eventName,0) 40 if curCount>1: 41 _pendingEventCountsByName[eventName]=(curCount-1) 42 elif curCount==1: 43 del _pendingEventCountsByName[eventName] 44 curCount=_pendingEventCountsByObj.get(obj,0) 45 if curCount>1: 46 _pendingEventCountsByObj[obj]=(curCount-1) 47 elif curCount==1: 48 del _pendingEventCountsByObj[obj] 49 curCount=_pendingEventCountsByNameAndObj.get((eventName,obj),0) 50 if curCount>1: 51 _pendingEventCountsByNameAndObj[(eventName,obj)]=(curCount-1) 52 elif curCount==1: 53 del _pendingEventCountsByNameAndObj[(eventName,obj)] 54 executeEvent(eventName,obj,**kwargs)
55
56 -def isPendingEvents(eventName=None,obj=None):
57 """Are there currently any events queued? 58 @param eventName: an optional name of an event type. If given then only if there are events of this type queued will it return True. 59 @type eventName: string 60 @param obj: the NVDAObject the event is for 61 @type obj: L{NVDAObjects.NVDAObject} 62 @returns: True if there are events queued, False otherwise. 63 @rtype: boolean 64 """ 65 if not eventName and not obj: 66 return bool(len(_pendingEventCountsByName)) 67 elif not eventName and obj: 68 return obj in _pendingEventCountsByObj 69 elif eventName and not obj: 70 return eventName in _pendingEventCountsByName 71 elif eventName and obj: 72 return (eventName,obj) in _pendingEventCountsByNameAndObj
73
74 -class _EventExecuter(object):
75 """Facilitates execution of a chain of event functions. 76 L{gen} generates the event functions and positional arguments. 77 L{next} calls the next function in the chain. 78 """ 79
80 - def __init__(self, eventName, obj, kwargs):
81 self.kwargs = kwargs 82 self._gen = self.gen(eventName, obj) 83 try: 84 self.next() 85 except StopIteration: 86 pass 87 del self._gen
88
89 - def next(self):
90 func, args = next(self._gen) 91 return func(*args, **self.kwargs)
92
93 - def gen(self, eventName, obj):
94 funcName = "event_%s" % eventName 95 96 # Global plugin level. 97 for plugin in globalPluginHandler.runningPlugins: 98 func = getattr(plugin, funcName, None) 99 if func: 100 yield func, (obj, self.next) 101 102 # App module level. 103 app = obj.appModule 104 if app: 105 func = getattr(app, funcName, None) 106 if func: 107 yield func, (obj, self.next) 108 109 # Tree interceptor level. 110 treeInterceptor = obj.treeInterceptor 111 if treeInterceptor: 112 func = getattr(treeInterceptor, funcName, None) 113 if func and (getattr(func,'ignoreIsReady',False) or treeInterceptor.isReady): 114 yield func, (obj, self.next) 115 116 # NVDAObject level. 117 func = getattr(obj, funcName, None) 118 if func: 119 yield func, ()
120
121 -def executeEvent(eventName,obj,**kwargs):
122 """Executes an NVDA event. 123 @param eventName: the name of the event type (e.g. 'gainFocus', 'nameChange') 124 @type eventName: string 125 @param obj: the object the event is for 126 @type obj: L{NVDAObjects.NVDAObject} 127 @param kwargs: Additional event parameters as keyword arguments. 128 """ 129 try: 130 sleepMode=obj.appModule.sleepMode if obj and obj.appModule else False 131 if eventName=="gainFocus" and not doPreGainFocus(obj,sleepMode=sleepMode): 132 return 133 elif not sleepMode and eventName=="documentLoadComplete" and not doPreDocumentLoadComplete(obj): 134 return 135 elif not sleepMode: 136 _EventExecuter(eventName,obj,kwargs) 137 except: 138 log.exception("error executing event: %s on %s with extra args of %s"%(eventName,obj,kwargs))
139
140 -def doPreGainFocus(obj,sleepMode=False):
141 oldForeground=api.getForegroundObject() 142 oldFocus=api.getFocusObject() 143 oldTreeInterceptor=oldFocus.treeInterceptor if oldFocus else None 144 api.setFocusObject(obj) 145 if globalVars.focusDifferenceLevel<=1: 146 newForeground=api.getDesktopObject().objectInForeground() 147 if not newForeground: 148 log.debugWarning("Can not get real foreground, resorting to focus ancestors") 149 ancestors=api.getFocusAncestors() 150 if len(ancestors)>1: 151 newForeground=ancestors[1] 152 else: 153 newForeground=obj 154 api.setForegroundObject(newForeground) 155 executeEvent('foreground',newForeground) 156 if sleepMode: return True 157 #Fire focus entered events for all new ancestors of the focus if this is a gainFocus event 158 for parent in globalVars.focusAncestors[globalVars.focusDifferenceLevel:]: 159 executeEvent("focusEntered",parent) 160 if obj.treeInterceptor is not oldTreeInterceptor: 161 if hasattr(oldTreeInterceptor,"event_treeInterceptor_loseFocus"): 162 oldTreeInterceptor.event_treeInterceptor_loseFocus() 163 if obj.treeInterceptor and obj.treeInterceptor.isReady and hasattr(obj.treeInterceptor,"event_treeInterceptor_gainFocus"): 164 obj.treeInterceptor.event_treeInterceptor_gainFocus() 165 return True
166
167 -def doPreDocumentLoadComplete(obj):
168 focusObject=api.getFocusObject() 169 if (not obj.treeInterceptor or not obj.treeInterceptor.isAlive or obj.treeInterceptor.shouldPrepare) and (obj==focusObject or obj in api.getFocusAncestors()): 170 ti=treeInterceptorHandler.update(obj) 171 if ti: 172 obj.treeInterceptor=ti 173 #Focus may be in this new treeInterceptor, so force focus to look up its treeInterceptor 174 focusObject.treeInterceptor=treeInterceptorHandler.getTreeInterceptor(focusObject) 175 return True
176