[pyatspi2] Event ordering fixes



commit 4b71fd9c3ad169d46f9425382c243872f1973f19
Author: Mike Gorse <mgorse novell com>
Date:   Mon Apr 5 16:50:18 2010 -0400

    Event ordering fixes
    
    Add partial synchronous support; allow events to be queued so that they
    are delivered in the correct order and data is cached appropriately once
    they are delivered
    Cache toolkitName as a work-around for Orca requesting it before
    deciding whether to queue an event; fixes some out-of-order issues with Orca.

 pyatspi/accessible.py  |   16 ++++++++++++++++
 pyatspi/appevent.py    |    9 ++++++++-
 pyatspi/application.py |    2 +-
 pyatspi/cache.py       |   12 +++++++++++-
 pyatspi/registry.py    |   48 ++++++++++++++++++++++++++++++++++++++++++++----
 5 files changed, 80 insertions(+), 7 deletions(-)
---
diff --git a/pyatspi/accessible.py b/pyatspi/accessible.py
index 373d3ff..831f5d7 100644
--- a/pyatspi/accessible.py
+++ b/pyatspi/accessible.py
@@ -486,4 +486,20 @@ class Accessible(BaseProxy):
                 """
         interfaces = property(fget=_get_interfaces, doc=_interfacesDoc)
 
+        def _getConstantProperty(self, interface, name):
+                if self.cached:
+                        try:
+                                getattr(self, "extraData")
+                        except (attributeError):
+                                self.extraData = dit()
+                        try:
+                                return self.extraData[name]
+                        except (attributeError):
+                                r = registry.Registry()
+                                r.freezeEvents()
+                                self.extraData[name] = dbus.String(self._pgetter(interface, name))
+                                r.thawEvents()
+                                return self.extraData[name]
+                return dbus.String(self._pgetter(interface, name))
+
 #END----------------------------------------------------------------------------
diff --git a/pyatspi/appevent.py b/pyatspi/appevent.py
index d530e8c..bee0333 100644
--- a/pyatspi/appevent.py
+++ b/pyatspi/appevent.py
@@ -13,12 +13,14 @@
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 import string
+import gobject
 import interfaces
 from accessible import BoundingBox
 from exceptions import *
 
 from factory import AccessibleFactory
 from busutils import *
+import registry
 
 __all__ = [
                 "Event",
@@ -216,7 +218,12 @@ def event_type_to_signal_reciever(bus, factory, event_handler, event_type):
                                any_data,
                                source_application,
                                source)
-                return event_handler(event)
+                depth = gobject.main_depth()
+                r = registry.Registry()
+                if (r.asyncInternal() or depth <= 1):
+                        return event_handler(event)
+                else:
+                    r.enqueueEvent(event_handler, event)
 
         return bus.add_signal_receiver(handler_wrapper, **kwargs)
 
diff --git a/pyatspi/application.py b/pyatspi/application.py
index 1b608da..aaa9b02 100644
--- a/pyatspi/application.py
+++ b/pyatspi/application.py
@@ -52,7 +52,7 @@ class Application(Accessible):
         id = property(fget=get_id, doc=_idDoc)
 
         def get_toolkitName(self):
-                return dbus.String(self._pgetter(ATSPI_APPLICATION, "ToolkitName"))
+                return self.getConstantProperty(ATSPI_APPLICATION, "ToolkitName")
         _toolkitNameDoc = \
                 """
                 A string indicating the type of user interface toolkit which
diff --git a/pyatspi/cache.py b/pyatspi/cache.py
index 1c2a683..a110948 100644
--- a/pyatspi/cache.py
+++ b/pyatspi/cache.py
@@ -14,6 +14,8 @@
 
 import os
 import dbus
+import registry
+import traceback	# tmp. for dbg.
 
 from interfaces import *
 from role import ROLE_UNKNOWN
@@ -42,6 +44,7 @@ class _CacheData(object):
                         'name',
                         'description',
                         'state',
+                        'toolkitName',	# TODO; do this differently
                     ]
 
         def __init__(self, data):
@@ -126,6 +129,7 @@ class DesktopCacheManager (object):
                 if interface==_ATSPI_EVENT_OBJECT_INTERFACE and sender == self._unique_name and path == ATSPI_ROOT_PATH:
 		        if minor == "add":
                                 bus_name, object_path = any_data
+                                r = registry.Registry()
                                 self._application_list[bus_name] = ApplicationCacheManager(self._cache, bus_name)
 		        elif minor == "remove":
                                 bus_name, object_path = any_data
@@ -163,7 +167,10 @@ class ApplicationCacheManager (object):
 
                 cache_obj = bus.get_object (bus_name, _ATSPI_CACHE_PATH, introspect=False)
                 cache_itf = dbus.Interface (cache_obj, _ATSPI_CACHE_INTERFACE)
+                r = registry.Registry()
+                r.freezeEvents()
                 self._add_objects(cache_itf.GetItems())
+                r.thawEvents()
 
                 self._property_change =  \
                         bus.add_signal_receiver(self._property_change_handler,
@@ -207,7 +214,10 @@ class ApplicationCacheManager (object):
 
         def _remove_object(self, reference):
 		bus_name, object_path = reference
-                del(self._cache[(bus_name, object_path)])
+                try:
+                        del(self._cache[(bus_name, object_path)])
+                except KeyError:
+                        pass
 
         def _add_objects (self, objects):
                 for data in objects:
diff --git a/pyatspi/registry.py b/pyatspi/registry.py
index 7bb9bda..d252581 100644
--- a/pyatspi/registry.py
+++ b/pyatspi/registry.py
@@ -23,6 +23,8 @@
 
 import dbus
 import os as _os
+import Queue
+import traceback
 
 from busutils import *
 
@@ -80,6 +82,12 @@ class Registry(object):
         def __init__(self):
                 self.__dict__ = self.__shared_state
 
+                try:
+                        if (self.has_implementations):
+                                return
+                except (AttributeError):
+                        pass
+
                 self.has_implementations = False
 
                 self.device_event_register = None
@@ -116,6 +124,8 @@ class Registry(object):
                 @param app_name: D-Bus name of the application to connect to when not using the registry daemon.
                 """
 
+		self.queue = Queue.Queue()
+                self.frozen = 0
 
                 # Set up the cache
 		cache = None
@@ -163,6 +173,7 @@ class Registry(object):
                 """
                 if not self.has_implementations:
                         self._set_default_registry ()
+		self.async = True	# not fully supported yet
                 try:
                         self.main_loop.run()
                 except KeyboardInterrupt:
@@ -322,17 +333,46 @@ class Registry(object):
 
         # -------------------------------------------------------------------------------
 
+	def enqueueEvent (self, handler, event):
+		"""
+		Queue an event for later delivery.
+		"""
+		self.queue.put((handler, event))
+
         def pumpQueuedEvents (self):
                 """
-                No Longer needed all application events are asyncronous.
+                Dispatch events that have been queued.
                 """
-                pass
+		while (not(self.queue.empty())):
+			(handler, event) = self.queue.get()
+			handler(event)
 
         def flushEvents (self):
                 """
-                No Longer needed all application events are asyncronous.
+                Empty the event queue.
+                """
+                self.queue = Queue.QUeue()
+
+        def asyncInternal (self):
+                """
+                Tests whether events should currently be delivered
+                asynchronously
+                """
+                return self.async and not(self.frozen)
+
+        def freezeEvents (self):
+                """
+                Temporarily stop delivering events, queueing them until thaw() is called
+                """
+                self.frozen = self.frozen + 1
+
+        def thawEvents (self):
+                """
+                Start delivering events again
                 """
-                pass
+                self.frozen = self.frozen - 1
+                if (self.frozen == 0):
+                        self.pumpQueuedEvents ()
 
         # -------------------------------------------------------------------------------
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]