Package AccessEngine :: Module AEViewManager'
[hide private]
[frames] | no frames]

Source Code for Module AccessEngine.AEViewManager'

  1  ''' 
  2  Defines a class responsible for handling events in the currently focused view. 
  3   
  4  @var CHECK_INTERVAL: Time in ms that the L{AEViewManager} will iterate over all 
  5    top level applications and provide them in a list to L{AETierManager} 
  6  @type CHECK_INTERVAL: integer 
  7  @var DEFAULT_EVENTS: Names of events that will be dispatched by the  
  8    L{AEViewManager} by default 
  9  @type DEFAULT_EVENTS: list 
 10   
 11  @author: Peter Parente 
 12  @author: Pete Brunet 
 13  @author: Brett Clippingdale 
 14  @organization: IBM Corporation 
 15  @copyright: Copyright (c) 2005, 2007 IBM Corporation 
 16   
 17  @author: Frank Zenker 
 18  @author: Ramona Bunk 
 19  @organization: IT Science Center Ruegen gGmbH, Germany 
 20  @copyright: Copyright (c) 2007, 2008 ITSC Ruegen 
 21   
 22  @license: I{The BSD License} 
 23  All rights reserved. This program and the accompanying materials are made  
 24  available under the terms of the BSD license which accompanies 
 25  this distribution, and is available at 
 26  U{http://www.opensource.org/licenses/bsd-license.php} 
 27  ''' 
 28  import pyatspi 
 29  import AccessEngine 
 30  from AEEvent import * 
 31  from AEPor import AEPor 
 32  from AEAccInterfaces import * 
 33  from AEWalkers import AccessibleWalker 
 34   
 35   
 36  # interval on which the manager will search for dead views 
 37  CHECK_INTERVAL = 60000 
 38   
 39  # events that we should always watch, regardless of Task interests 
 40  DEFAULT_EVENTS = [ViewChange, FocusChange, SelectorChange, CaretChange,  
 41                    PropertyChange, PrivateChange] 
 42   
43 -class _AEViewManager(object):
44 ''' 45 Stores a root accessible representing the active view when an event occurs 46 indicating that the view may have changed. 47 48 Two view roots must be tracked 49 by this object. The first, the raw view, is needed by L{AEAccAdapters} which will 50 handle raw view change events. The second, the L{AccessEngine} view, is 51 needed by the rest of the system when processing L{AEEvent <AEEvent.AEEvent>}s. 52 53 @ivar raw_view: Root accessible representing the active view according to the 54 raw event stream. 55 @type raw_view: C{pyatspi.Accessible} 56 @ivar ae_view: Root L{AEPor} representing the active view according to the 57 L{AEEvent <AEEvent.AEEvent>} stream. 58 @type ae_view: L{AEPor} 59 @ivar wanted_events: Lookup table for what L{AEEvent <AEEvent.AEEvent>}s are 60 desired by any task in any L{AEScript <AEScript.AEScript>} in all L{AETier}s. 61 62 Used to optimize event dispatch and processing. Unwanted events are ignored. 63 @type wanted_events: dictionary 64 @ivar raw_active: Is there an raw active view? 65 @type raw_active: boolean 66 '''
67 - def __init__(self):
68 ''' 69 Initializes active view to C{None}. 70 ''' 71 self.raw_view = None 72 self.wanted_events = {} 73 self.raw_active = False 74 self.ae_view = None 75 # register for a callback to check living applications 76 AccessEngine.AEMain.addTimer(self.onIterateApps, CHECK_INTERVAL)
77
78 - def init(self):
79 ''' 80 Registers with the L{AEEventManager} to receive raw events related to the 81 active view. 82 83 Also registers for raw events that may indicate that this 84 L{AEViewManager} needs to manage a new view. 85 86 Called by L{AEMain} at startup. 87 ''' 88 # register for events that almost certainly mean the view has changed 89 AccessEngine.AEEventManager.acc_reg.registerEventListener(self.onRawViewEvent, 90 *IEventHandler().getRawEvents(ViewChange)) 91 # track how many dependencies we have on a certain kind of event 92 for kind in DEFAULT_EVENTS: 93 self.setEventInterest(kind, True)
94
95 - def close(self):
96 '''Does nothing and is called by L{AEMain} when quitting the main loop.''' 97 pass
98
99 - def initViews(self):
100 ''' 101 Walks through the top level applications on the first desktop. 102 103 Calls the method C{AETierManager.createAETier} for application encountered. 104 If the L{AETierManager} determines that an app has at least one 105 L{AEScript <AEScript.AEScript>} written for that application, creates an 106 L{AETier} for the application and loads all of 107 its L{AEScript <AEScript.AEScript>}s. 108 109 If the L{AETier} is created, this method sends 110 L{AEEvent.ViewChange} messages to the L{AETier} with a flag of 111 L{AEConstants.Event.EVENT_VIEW_STARTUP} such that L{AEScript <AEScript.AEScript>}s in the L{AETier} 112 may initialize themselves and begin any desired background processes. 113 ''' 114 try: 115 d = pyatspi.Registry.getDesktop(0) 116 except Exception: 117 # just stop if we get an error right away 118 return 119 ai = IAccessibleInfo(AEPor(d)) 120 an = IAccessibleNav(AEPor(d)) 121 events = [] 122 # iterate over all children of the desktop 123 for i in xrange(ai.getAccChildCount()): 124 try: 125 app = an.getChildAcc(i) 126 except (LookupError, IndexError): 127 continue 128 # get application names and IDs 129 aai = IAccessibleInfo(app) 130 aid = aai.getAccAppID() 131 name = aai.getAccAppName() 132 # inform the tier manager 133 if AccessEngine.AETierManager.createAETier(name, aid, app, True) is not None: 134 events.append(ViewChange(app, AEConstants.EVENT_VIEW_STARTUP)) 135 # if we've found the active app, just continue 136 if self.raw_view is not None: 137 continue 138 aan = IAccessibleNav(app) 139 # iterate over all top level windows in the app 140 for x in xrange(aai.getAccChildCount()): 141 try: 142 win = aan.getChildAcc(x) 143 except (LookupError, IndexError): 144 continue 145 # look for one that has state active 146 wai = IAccessibleInfo(win) 147 if wai.hasAccState('active'): 148 self.raw_view = win 149 self.raw_active = True 150 break 151 # send a view change gained event to the active tier 152 if self.raw_view is not None: 153 events.append(ViewChange(self.raw_view, 154 AEConstants.EVENT_VIEW_FIRST_GAINED)) 155 AccessEngine.AEEventManager.postEvents(*events)
156
157 - def setEventInterest(self, kind, wants):
158 ''' 159 Sets or unsets an interest in a particular kind of 160 L{AEEvent <AEEvent.AEEvent>}. 161 162 This information is used to register or unregister for raw events on-demand 163 as an optimization. 164 165 @param kind: Indicates the type of L{AEEvent <AEEvent.AEEvent>} some part of 166 the system wants to be able to process 167 @type kind: L{AEEvent <AEEvent.AEEvent>} 168 @param wants: Does the system want to process the given kind of 169 L{AEEvent <AEEvent.AEEvent>}? 170 @type wants: boolean 171 ''' 172 count = self.wanted_events.setdefault(kind, 0) 173 if wants: 174 count += 1 175 else: 176 count -= 1 177 if count <= 0: 178 del self.wanted_events[kind] 179 AccessEngine.AEEventManager.acc_reg.deregisterEventListener(self.onRawEvent, 180 *IEventHandler().getRawEvents(kind)) 181 return 182 elif count == 1: 183 AccessEngine.AEEventManager.acc_reg.registerEventListener(self.onRawEvent, 184 *IEventHandler().getRawEvents(kind)) 185 self.wanted_events[kind] = count
186
187 - def getRawActive(self):
188 ''' 189 Gets whether some view is active or not. 190 191 @return: Value of L{raw_active} 192 @rtype: boolean 193 ''' 194 return self.raw_active
195
196 - def setRawActive(self, val):
197 ''' 198 Sets whether some view is active or not. 199 200 @param val: Value to store in L{raw_active} 201 @type val: boolean 202 ''' 203 self.raw_active = val
204
205 - def getRawView(self):
206 ''' 207 Gets the root L{AEPor} of the active view according to the raw event 208 stream. 209 210 This is the view known to L{AEAccAdapters}. 211 212 @see: L{setRawView} 213 @return: Root L{AEPor} of the raw active view 214 @rtype: L{AEPor} 215 ''' 216 return self.raw_view
217
218 - def setRawView(self, accessible):
219 ''' 220 Stores the root L{AEPor} of the active view according to the raw event 221 stream. 222 223 This is the view known to L{AEAccAdapters}. 224 225 @see: L{getRawView} 226 @param accessible: Event source that triggered the change of view. Usually 227 a top level window or panel. 228 @type accessible: C{pyatspi.Accessible} 229 @return: Was a new view root set or not? 230 @rtype: boolean 231 ''' 232 rv = False 233 # walk to the first POR 234 root = AEPor(accessible) 235 # see if it is different from our current root POR 236 if root != self.raw_view: 237 # store the new view 238 self.raw_view = root 239 rv = True 240 return rv
241
242 - def getAEView(self):
243 ''' 244 Gets the root L{AEPor} of the active view according to the 245 L{AEEvent <AEEvent.AEEvent>} stream. 246 247 This is the view known to L{AEScript <AEScript.AEScript>}s. 248 249 @see: L{setAEView} 250 @return: Root L{AEPor} of the active L{AEMain} view 251 @rtype: L{AEPor} 252 ''' 253 return self.ae_view
254
255 - def setAEView(self, por):
256 ''' 257 Stores the root L{AEPor} of the active view according to the 258 L{AEEvent <AEEvent.AEEvent>} stream. 259 260 This is the view known to L{AEAccAdapters}. 261 262 @see: L{getAEView} 263 @param por: New root L{AEPor} of the active L{AEMain} view. May 264 be set to C{None} if there is no active view. 265 @type por: L{AEPor} 266 ''' 267 self.ae_view = por
268
269 - def onIterateApps(self):
270 ''' 271 Collects all application names and IDs and gives them to the L{AETierManager} 272 so it can free any L{AETier}s that are no longer associated with running 273 applications. 274 275 @return: C{True} to continue receiving notifications 276 @rtype: boolean 277 ''' 278 try: 279 d = pyatspi.Registry.getDesktop(0) 280 except Exception: 281 # stop if we get an error immediately 282 return 283 ai = IAccessibleInfo(AEPor(d)) 284 an = IAccessibleNav(AEPor(d)) 285 aids = [] 286 # iterate over all children of the desktop 287 for i in xrange(ai.getAccChildCount()): 288 try: 289 app = an.getChildAcc(i) 290 except (LookupError, IndexError): 291 continue 292 # get all application identifiers 293 aai = IAccessibleInfo(app) 294 aids.append(aai.getAccAppID()) 295 # inform the AETierManager about the living applications 296 AccessEngine.AETierManager.freeDeadAETiers(aids) 297 return True
298
299 - def onRawEvent(self, event):
300 ''' 301 Based on a raw C{pyatspi.event.Event} posts L{AEEvent <AEEvent.AEEvent>}s 302 to the active L{AETier} through the L{AEEventManager}. 303 304 @param event: Event indicating some change 305 @type event: C{pyatspi.event.Event} 306 ''' 307 # only forward events if there is a view 308 if self.raw_view is not None: 309 try: 310 eh = IEventHandler(event.source) 311 eh.getAEEvents(event, AccessEngine.AEEventManager.postEvents) 312 except LookupError: 313 # ignore dead accessibles 314 return
315
316 - def onRawViewEvent(self, event):
317 ''' 318 Creates a L{AEEvent.ViewChange} event in response to a window activation or 319 deactivation. 320 321 Also responds to create or destroy events from floating 322 windows. Called in response to any of the raw events returned by 323 L{AEAccInterfaces.IEventHandler.getAEViewEvents} and registered with the 324 L{AEEventManager} in the C{AEViewManager.init} method when this object was 325 created. 326 327 @param event: Event that may indicate the view has changed 328 @type event: C{pyatspi.event.Event} 329 ''' 330 try: 331 eh = IEventHandler(event.source) 332 eh.getAEViewEvents(event, AccessEngine.AEEventManager.postEvents, self) 333 except LookupError: 334 # ignore dead accessibles 335 return
336