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

Source Code for Module EventManager

  1  ''' 
  2  Defines a class that extends L{pyLinAcc.Event.Manager} to support L{AEEvent}s. 
  3   
  4  @var MAX_EVENT: Maximum number of raw or L{AEEvent}s to process in a single 
  5    callback from the main loop 
  6  @type MAX_EVENTS: integer 
  7  @var EVENT_INTERVAL: Number of ms between calls to pump the event queues 
  8  @type EVENT_INTERVAL: integer 
  9   
 10  @author: Peter Parente 
 11  @author: Pete Brunet 
 12  @organization: IBM Corporation 
 13  @copyright: Copyright (c) 2005, 2007 IBM Corporation 
 14  @license: The BSD License 
 15   
 16  All rights reserved. This program and the accompanying materials are made 
 17  available under the terms of the BSD license which accompanies 
 18  this distribution, and is available at 
 19  U{http://www.opensource.org/licenses/bsd-license.php} 
 20  ''' 
 21  import pyLinAcc 
 22  import Queue, time, logging 
 23  import AEEvent, AEMonitor, UIRegistrar, AEConstants 
 24  from AEInterfaces import implements 
 25  from UIRegistrar import MONITOR 
 26  from i18n import _ 
 27   
 28  log = logging.getLogger('Event') 
 29  EVENT_INTERVAL = 10 
 30  MAX_EVENTS = 10 
 31   
32 -class EventManager(pyLinAcc.Event.Manager):
33 ''' 34 Watches for AT-SPI events and reports them to observers. Maintains a queue 35 of L{AEEvent} that are executed on a set interval. 36 37 @ivar acc_eng: Reference to the L{AccessEngine} object 38 @type acc_eng: L{AccessEngine} 39 @ivar view_manager: Reference to the L{ViewManager} object 40 @type view_manager: L{ViewManager} 41 @ivar tier_manager: Reference to the L{TierManager} object 42 @type tier_manager: L{TierManager} 43 @ivar raw_queue: FIFO queue of L{pyLinAcc.Event.Event}s to be dispatched 44 @type raw_queue: Queue.Queue 45 @ivar ae_queue: FIFO queue of L{AEEvent} to be executed 46 @type ae_queue: Queue.Queue 47 @ivar timer_id: ID of the timer pumping the event queue 48 @type timer_id: integer 49 @ivar last_event: 50 @type last_event: L{AEEvent} 51 '''
52 - def __init__(self, acc_eng):
53 ''' 54 Initializes the parent class. Creates an event queue. Asks the 55 L{AccessEngine} to schedule interval callbacks to the 56 L{EventManager.onPumpRawEvents} and L{EventManager.onPumpAEEvents} methods. 57 58 @param acc_eng: Reference to the L{AccessEngine} that created this manager 59 @type acc_eng: L{AccessEngine} 60 ''' 61 pyLinAcc.Event.Manager.__init__(self) 62 self.acc_eng = acc_eng 63 self.ae_queue = Queue.Queue() 64 self.raw_queue = Queue.Queue() 65 self.monitors = AEMonitor.MonitorCollection() 66 self.last_event = None 67 68 # ask the access engine to notify us on a set interval to pump both the 69 # raw and AE event queues 70 self.acc_eng.addTimer(self.onPumpRawEvents, EVENT_INTERVAL) 71 self.acc_eng.addTimer(self.onPumpAEEvents, EVENT_INTERVAL)
72
73 - def init(self, view_man, tier_man, **kwargs):
74 ''' 75 Stores references to the L{ViewManager} and L{TierManager}. Instantiates all 76 L{AEMonitor} UIEs registered with L{UIRegistrar} to be loaded at startup. 77 Called by L{AccessEngine} at startup. 78 79 @param tier_man: Reference to the L{TierManager} 80 @type tier_man: L{TierManager} 81 @param view_man: Reference to the L{ViewManager} 82 @type view_man: L{ViewManager} 83 @param kwargs: References to managers not of interest here 84 @type kwargs: dictionary 85 ''' 86 # store other manager references 87 self.view_manager = view_man 88 self.tier_manager = tier_man 89 # load all startup monitors 90 reg = UIRegistrar 91 mons = reg.loadAssociated(MONITOR, self.acc_eng.getProfile()) 92 self.addMonitors(*mons)
93
94 - def close(self):
95 ''' 96 Throws away all events in the L{raw_queue} and L{ae_queue}. Calls the parent 97 class close method. 98 ''' 99 super(EventManager, self).close() 100 self.raw_queue = Queue.Queue() 101 self.ae_queue = Queue.Queue() 102 self.monitors.clear()
103
104 - def addMonitors(self, *monitors):
105 ''' 106 Adds one or more L{AEMonitor}s to the list of monitors to be 107 notified about events. 108 109 @param monitors: L{AEMonitor}s to notify 110 @type monitors: tuple of L{AEMonitor}s 111 ''' 112 self.monitors.add(pyLinAcc.Event.Event, monitors)
113
114 - def getMonitors(self):
115 ''' 116 @return: Collection of all loaded L{AEMonitor}s 117 @rtype: L{AEMonitor.MonitorCollection} 118 ''' 119 return self.monitors
120
121 - def showEvent(self, event):
122 ''' 123 Informs L{AEMonitor}s added via L{addMonitors} of a raw event. 124 125 @param event: Raw accessibility event 126 @type event: L{pyLinAcc.Event.Event} 127 ''' 128 self.monitors.show(event=event)
129
130 - def _executeEvent(self, event):
131 ''' 132 Executes the provided L{AEEvent}. Provides references to all managers as 133 named parameters to the event's execute method. Catches and logs all 134 exceptions to prevent bad events from getting re-queued for later execution. 135 136 @param event: Event to execute 137 @type event: L{AEEvent} 138 @return: Did the event execute properly or does it need to be re-queued for 139 later execution? 140 @rtype: True 141 ''' 142 # don't let our pump die if something fails 143 try: 144 return event.execute(view_manager=self.view_manager, 145 tier_manager=self.tier_manager, 146 event_manager=self) 147 except LookupError: 148 # just ignore dead objects 149 return True 150 except Exception, e: 151 # don't get bad events stuck in a loop 152 log.exception(str(e)) 153 return True
154
155 - def flushEvents(self):
156 ''' 157 Flushes the event queue by destroying it and recreating it. 158 ''' 159 self.ae_queue = Queue.Queue() 160 self.raw_queue = Queue.Queue()
161
162 - def postEvents(self, *events):
163 ''' 164 Add L{AEEvent}s to the queue. Events can be added by any part of the system 165 Events marked with immediate priority are executed now instead of being 166 added to the queue. Immediate execution is necessary for some kinds of 167 events. 168 169 @param events: Events to queue for dispatch 170 @type events: tuple of L{AEEvent}s 171 ''' 172 for e in events: 173 if e is not None: 174 if e.priority == AEConstants.EXEC_IMMEDIATE: 175 # some events need to execute immediately (e.g. view update) 176 if self._executeEvent(e) == False: 177 # if it doesn't work now, try again later 178 log.debug('re-queuing immediate AEEvent') 179 self.ae_queue.put_no_wait(e) 180 else: 181 self.ae_queue.put_nowait(e)
182
183 - def handleEvent(self, event):
184 ''' 185 Overrides the base implementation of L{handleEvent} so that all 186 L{pyLinAcc.Event.Event}s of interest are queued rather than immediately 187 dispatched. This breaks the synchronous connection between LSR and the rest 188 of the desktop. See L{pyLinAcc.Event.Manager.handleEvent} for more details. 189 190 @param event: Wrapped AT-SPI event 191 @type event: L{pyLinAcc.Event.Event} 192 ''' 193 self.raw_queue.put_nowait(event)
194
195 - def onPumpRawEvents(self):
196 ''' 197 Pumps all L{pyLinAcc.Event.Event}s in the L{raw_queue}. Calls the inherited 198 L{pyLinAcc.Event.Manager._dispatchEvent} method to forward to the event to 199 all registered clients. Catches and logs all exceptions to prevent them 200 from propogating to the main loop that called this method. 201 202 This method is called on a set interval by the main event loop in 203 L{AccessEngine.AccessEngine.run}. It is registered for callbacks in the 204 constructor of this class. 205 206 @return: True to continue receiving notifications 207 @rtype: boolean 208 ''' 209 for i in xrange(MAX_EVENTS): 210 try: 211 # get next waiting events 212 event = self.raw_queue.get_nowait() 213 except Queue.Empty: 214 break 215 # notify monitors that the event was received 216 self.showEvent(event) 217 try: 218 self._dispatchEvent(event) 219 except LookupError: 220 break 221 except Exception: 222 # catch all exceptions to prevent our main loop from dying 223 log.exception('Raw event exception') 224 return True
225
226 - def onPumpAEEvents(self):
227 ''' 228 Pumps all L{AEEvent}s in the L{ae_queue}. Executes each event pumped. 229 Re-queues events for later execution that return False from their execute 230 methods. 231 232 This method is called on a set interval by the main event loop in 233 L{AccessEngine.AccessEngine.run}. It is registered for callbacks in the 234 constructor of this class. 235 236 @return: True to continue receiving notifications 237 @rtype: boolean 238 ''' 239 later = [] 240 for i in xrange(MAX_EVENTS): 241 try: 242 event = self.ae_queue.get_nowait() 243 except Queue.Empty: 244 break 245 rv = self._executeEvent(event) 246 if rv == False: 247 # try to execute the event again later 248 later.append(event) 249 log.debug('re-queuing AEEvent') 250 self.last_event = event 251 # put all events that failed to execute back in the queue for later 252 map(self.postEvents, later) 253 return True
254