X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=pyatspi%2Fregistry.py;h=de37259873a5043ec83c8f74273dc9f53b20145c;hb=4ad06c974fbd6f5c470feea26700073d5800b24d;hp=0ff0eb0f763502935736b2b023b00a367fdf648e;hpb=5e43c51b4e5324b3bebdc29a4d8ed26a8a4d1bb4;p=platform%2Fcore%2Fuifw%2Fat-spi2-atk.git diff --git a/pyatspi/registry.py b/pyatspi/registry.py index 0ff0eb0..de37259 100644 --- a/pyatspi/registry.py +++ b/pyatspi/registry.py @@ -146,7 +146,7 @@ class _DeviceObserver(_Observer, Accessibility__POA.DeviceEventListener): @type key_set: list of integer @param mask: Integer modifier mask or an iterable over multiple masks to unapply all at once - @type mask: integer or iterable + @type mask: integer, iterable, or None @param kind: Kind of events to monitor @type kind: integer ''' @@ -171,7 +171,7 @@ class _DeviceObserver(_Observer, Accessibility__POA.DeviceEventListener): @type key_set: list of integer @param mask: Integer modifier mask or an iterable over multiple masks to unapply all at once - @type mask: integer or iterable + @type mask: integer, iterable, or None @param kind: Kind of events to monitor @type kind: integer ''' @@ -180,12 +180,10 @@ class _DeviceObserver(_Observer, Accessibility__POA.DeviceEventListener): iter(mask) except TypeError: # unregister a single integer if not - dc.deregisterKeystrokeListener(self._this(), key_set, mask, kind, - self.mode) + dc.deregisterKeystrokeListener(self._this(), key_set, mask, kind) else: for m in mask: - dc.deregisterKeystrokeListener(self._this(), key_set, m, kind, - self.mode) + dc.deregisterKeystrokeListener(self._this(), key_set, m, kind) def queryInterface(self, repo_id): ''' @@ -206,9 +204,8 @@ class _DeviceObserver(_Observer, Accessibility__POA.DeviceEventListener): ''' 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 @@ -218,8 +215,7 @@ class _DeviceObserver(_Observer, Accessibility__POA.DeviceEventListener): ''' # 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): ''' @@ -335,22 +331,32 @@ class Registry(object): ''' self.async = async - # register a signal handler for gracefully killing the loop - signal.signal(signal.SIGINT, self.stop) - signal.signal(signal.SIGTERM, self.stop) - if gil: def releaseGIL(): - time.sleep(1e-5) + try: + time.sleep(1e-5) + except KeyboardInterrupt, e: + # store the exception for later + releaseGIL.keyboard_exception = e + self.stop() return True + # make room for an exception if one occurs during the + releaseGIL.keyboard_exception = None i = gobject.idle_add(releaseGIL) # enter the main loop - bonobo.main() - - if gil: - gobject.source_remove(i) - + try: + bonobo.main() + finally: + # clear all observers + for name, ob in self.observers.items(): + ob.unregister(self.reg, name) + if gil: + gobject.source_remove(i) + if releaseGIL.keyboard_exception is not None: + # raise an keyboard exception we may have gotten earlier + raise releaseGIL.keyboard_exception + def stop(self, *args): '''Quits the main loop.''' try: @@ -358,6 +364,7 @@ class Registry(object): except RuntimeError: # ignore errors when quitting (probably already quitting) pass + self.flushEvents() def getDesktopCount(self): ''' @@ -453,7 +460,7 @@ class Registry(object): the mask are held. When the mask is an iterable over more than one integer, keys in the key_set will be monitored when any of the modifier combinations in the set are held. - @type mask: integer + @type mask: integer, iterable, None @param kind: Kind of events to watch, KEY_PRESSED_EVENT or KEY_RELEASED_EVENT. @type kind: list @@ -476,6 +483,9 @@ class Registry(object): # store the observer to client mapping, and the inverse self.clients[ob] = client self.clients[client] = ob + if mask is None: + # None means all modifier combinations + mask = utils.allModifiers() # register for new keystrokes on the observer ob.register(self.dev, key_set, mask, kind) @@ -496,7 +506,7 @@ class Registry(object): the mask are held. When the mask is an iterable over more than one integer, keys in the key_set will be monitored when any of the modifier combinations in the set are held. - @type mask: integer + @type mask: integer, iterable, None @param kind: Kind of events to stop watching, KEY_PRESSED_EVENT or KEY_RELEASED_EVENT. @type kind: list @@ -504,6 +514,9 @@ class Registry(object): ''' # see if we already have an observer for this client ob = self.clients[client] + if mask is None: + # None means all modifier combinations + mask = utils.allModifiers() # register for new keystrokes on the observer ob.unregister(self.dev, key_set, mask, kind) @@ -546,10 +559,9 @@ class Registry(object): ''' 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. @@ -558,16 +570,20 @@ class Registry(object): @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() @@ -591,30 +607,74 @@ class Registry(object): ''' 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 @@ -731,5 +791,5 @@ class Registry(object): ob = self.observers[et.name] ob.clientUnref() if ob.getClientRefCount() == 0: - ob.unregister(self.registry, name) + ob.unregister(self.reg, name) del self.observers[et.name]