'''
Notifies the L{Registry} that an event has occurred. Wraps the raw event
object in our L{Event} class to support automatic ref and unref calls. An
- observer can set the L{Event} consume flag to True to indicate this event
- should not be allowed to pass to other AT-SPI observers or the underlying
- application.
+ observer can return True to indicate this event should not be allowed to pass
+ to other AT-SPI observers or the underlying application.
@param ev: Keyboard event
@type ev: Accessibility.DeviceEvent
'''
# wrap the device event
ev = event.DeviceEvent(ev)
- self.registry.handleDeviceEvent(ev, self)
- return ev.consume
+ return self.registry.handleDeviceEvent(ev, self)
class _EventObserver(_Observer, Accessibility__POA.EventListener):
'''
# enter the main loop
try:
bonobo.main()
- except KeyboardInterrupt, e:
- # re-raise the keyboard interrupt
- raise e
finally:
# clear all observers
for name, ob in self.observers.items():
if gil:
gobject.source_remove(i)
if releaseGIL.keyboard_exception is not None:
- # re-raise the keyboard interrupt we got during the GIL release
+ # raise an keyboard exception we may have gotten earlier
raise releaseGIL.keyboard_exception
def stop(self, *args):
except RuntimeError:
# ignore errors when quitting (probably already quitting)
pass
+ self.flushEvents()
def getDesktopCount(self):
'''
'''
Dispatches L{event.DeviceEvent}s to registered clients. Clients are called
in the order they were registered for the given AT-SPI event. If any
- client sets the L{event.DeviceEvent.consume} flag to True, callbacks cease
- for the event for clients of this registry instance. Clients of other
- registry instances and clients in other processes may be affected
- depending on the values of synchronous and preemptive used when invoking
+ client returns True, callbacks cease for the event for clients of this registry
+ instance. Clients of other registry instances and clients in other processes may
+ be affected depending on the values of synchronous and preemptive used when invoking
L{registerKeystrokeListener}.
@note: Asynchronous dispatch of device events is not supported.
@type event: L{event.DeviceEvent}
@param ob: Observer that received the event
@type ob: L{_DeviceObserver}
+
+ @return: Should the event be consumed (True) or allowed to pass on to other
+ AT-SPI observers (False)?
+ @rtype: boolean
'''
try:
# try to get the client registered for this event type
client = self.clients[ob]
except KeyError:
# client may have unregistered recently, ignore event
- return
+ return False
# make the call to the client
try:
- client(event)
+ return client(event) or event.consume
except Exception:
# print the exception, but don't let it stop notification
traceback.print_exc()
'''
Dispatches L{event.Event}s to registered clients. Clients are called in
the order they were registered for the given AT-SPI event. If any client
- sets the L{Event} consume flag to True, callbacks cease for the event for
- clients of this registry instance. Clients of other registry instances and
- clients in other processes are unaffected.
+ returns True, callbacks cease for the event for clients of this registry
+ instance. Clients of other registry instances and clients in other processes
+ are unaffected.
@param event: AT-SPI event
@type event: L{event.Event}
'''
+ et = event.type
try:
# try to get the client registered for this event type
- clients = self.clients[event.type.name]
+ clients = self.clients[et.name]
except KeyError:
- # client may have unregistered recently, ignore event
- return
+ try:
+ # we may not have registered for the complete subtree of events
+ # if our tree does not list all of a certain type (e.g.
+ # object:state-changed:*); try again with klass and major only
+ if et.detail is not None:
+ # Strip the 'detail' field.
+ clients = self.clients['%s:%s:%s' % (et.klass, et.major, et.minor)]
+ elif et.minor is not None:
+ # The event could possibly be object:state-changed:*.
+ clients = self.clients['%s:%s' % (et.klass, et.major)]
+ except KeyError:
+ # client may have unregistered recently, ignore event
+ return
# make the call to each client
+ consume = False
for client in clients:
try:
- client(event)
+ consume = client(event) or False
except Exception:
# print the exception, but don't let it stop notification
traceback.print_exc()
- if event.consume:
- # don't allow further processing if the consume flag is set
+ if consume or event.consume:
+ # don't allow further processing if a client returns True
break
+ def flushEvents(self):
+ '''
+ Flushes the event queue by destroying it and recreating it.
+ '''
+ self.queue = Queue.Queue()
+
+ def pumpQueuedEvents(self, num=-1):
+ '''
+ Provides asynch processing of events in the queue by executeing them with
+ _dispatchEvent() (as is done immediately when synch processing).
+ This method would normally be called from a main loop or idle function.
+
+ @param num: Number of events to pump. If number is negative it pumps
+ the entire queue. Default is -1.
+ @type num: integer
+ @return: True if queue is not empty after events were pumped.
+ @rtype: boolean
+ '''
+ if num < 0:
+ # Dequeue as many events as currently in the queue.
+ num = self.queue.qsize()
+ for i in xrange(num):
+ try:
+ # get next waiting event
+ event = self.queue.get_nowait()
+ except Queue.Empty:
+ break
+ self._dispatchEvent(event)
+
+ return not self.queue.empty()
+
def _registerClients(self, client, name):
'''
Internal method that recursively associates a client with AT-SPI event