[pyatspi2] Added a weak-ref-based "soft cache"



commit ef0b55bef623d0306bb15959d7351a57da0a2db6
Author: Mike Gorse <mgorse novell com>
Date:   Sat Oct 2 06:00:40 2010 -0400

    Added a weak-ref-based "soft cache"
    
    Added a "soft" cache to store the roles/state/parents returned from explicit
    queries.  In theory this should not be needed, but sometimes we don't receive
    an AccessibleAdded when an object is created.

 pyatspi/accessible.py |   30 ++++++++++++++++++++++++++----
 pyatspi/cache.py      |   33 ++++++++++++++++++++++++++++++---
 2 files changed, 56 insertions(+), 7 deletions(-)
---
diff --git a/pyatspi/accessible.py b/pyatspi/accessible.py
index 0c7e633..d145877 100644
--- a/pyatspi/accessible.py
+++ b/pyatspi/accessible.py
@@ -95,6 +95,12 @@ class BoundingBox(list):
 
 #------------------------------------------------------------------------------
 
+class _PropertyCache(dict):
+  def wipe(self):
+      self.__dict__ = {}
+
+#------------------------------------------------------------------------------
+
 class AccessibleMeta(type):
         def __new__(meta, *args, **kwargs):
                 cls = type.__new__(meta, *args, **kwargs)
@@ -207,6 +213,11 @@ class Accessible(BaseProxy):
 		self._cache = cache
 
                 self._relation_set = None
+                try:
+                        self._soft_cache_data = self._cache.soft[(self._app_name, self._acc_path)]
+                except KeyError:
+                        self._soft_cache_data = _PropertyCache()
+                        self._cache.soft[(self._app_name, self._acc_path)] = self._soft_cache_data
 
         # Python object protocol --------------------------------------------------------
 
@@ -412,7 +423,7 @@ class Accessible(BaseProxy):
                         return Role(self._cached_data.role)
                 else:
                         func = self.get_dbus_method("GetRole", dbus_interface=ATSPI_ACCESSIBLE)
-                        return Role(func())
+                        return Role(self.getSoftCacheItem ("role", func))
 
         def getRoleName(self):
                 """
@@ -436,7 +447,7 @@ class Accessible(BaseProxy):
                 else:
                         func = self.get_dbus_method("GetState", dbus_interface=ATSPI_ACCESSIBLE)
                         try:
-                                return _marshal_state_set(func())
+                                return _marshal_state_set(self.getSoftCacheItem("state", func))
                         except LookupError:
                                 return _marshal_state_set ([1 << STATE_DEFUNCT, 0])
 
@@ -493,7 +504,7 @@ class Accessible(BaseProxy):
                 if self.cached:
                         name, path = self._cached_data.parent
                 else:
-		        name, path = self._pgetter (ATSPI_ACCESSIBLE, "Parent")
+		        name, path = self.getSoftCacheProperty (ATSPI_ACCESSIBLE, "Parent")
 
                 if (path == ATSPI_ROOT_PATH):
                         itf = ATSPI_APPLICATION
@@ -511,13 +522,14 @@ class Accessible(BaseProxy):
                         return self._cached_data.interfaces
                 else:
                         func = self.get_dbus_method("GetInterfaces", dbus_interface=ATSPI_ACCESSIBLE)
-                        return func()
+                        return self.getSoftCacheItem("interfaces", func)
         _interfacesDoc = \
                 """
                 D-Bus interfaces supported by this accessible object.
                 """
         interfaces = property(fget=_get_interfaces, doc=_interfacesDoc)
 
+        # TODO: Possibly merge this with getSoftCacheItem
         def _getConstantProperty(self, interface, name):
                 if self.cached:
                         try:
@@ -531,4 +543,14 @@ class Accessible(BaseProxy):
                                 return self.extraData[name]
                 return dbus.String(self._pgetter(interface, name))
 
+        def getSoftCacheItem(self, name, func):
+                if not(name in self._soft_cache_data):
+                        self._soft_cache_data[name] = func()
+                return self._soft_cache_data[name]
+
+        def getSoftCacheProperty(self, interface, name):
+                if not((interface, name) in self._soft_cache_data):
+                        self._soft_cache_data[(interface, name)] = self._pgetter(interface, name)
+                return self._soft_cache_data[(interface, name)]
+
 #END----------------------------------------------------------------------------
diff --git a/pyatspi/cache.py b/pyatspi/cache.py
index b0ce9d1..bf5483d 100644
--- a/pyatspi/cache.py
+++ b/pyatspi/cache.py
@@ -16,6 +16,7 @@ import os
 import dbus
 import registry
 import string
+import weakref
 
 from interfaces import *
 from role import ROLE_DESKTOP_FRAME
@@ -277,6 +278,17 @@ class ApplicationCacheManager (object):
                                 elif minor == "accessible-parent":
                                         item.parent = any_data
 
+                        if (sender, path) in self._cache.soft:
+                                item = self._cache.soft[(sender, path)]
+                                if minor == "accessible-name":
+                                        item["name"] = any_data
+                                elif minor == "accessible-role":
+                                        item["role"] = any_data
+                                elif minor == "accessible-description":
+                                        item["description"] = any_data
+                                elif minor == "accessible-parent":
+                                        item[(ATSPI_ACCESSIBLE, "parent")] = any_data
+
         def _children_changed_handler (self,
                                        minor, detail1, detail2, any_data, app,
                                        interface=None, sender=None, member=None, path=None):
@@ -289,25 +301,38 @@ class ApplicationCacheManager (object):
                                         item.children.insert (detail1, any_data)
                                 elif minor.startswith("remove"):
                                         item.children.remove (any_data)
+
                                         if any_data in self._cache:
                                                 child = self._cache[any_data]
                                                 if child.parent == (sender, path):
                                                         child.parent = (sender, ATSPI_NULL_PATH)
+                                        if any_data in self._cache.soft:
+                                                child = self._cache.soft[any_data]
+                                                if (ATSPI_ACCESSIBLE, "Parent") in child and child[(ATSPI_ACCESSIBLE, "Parent")] == (sender, path):
+                                                        child[(ATSPI_ACCESSIBLE, "Parent")] = (sender, ATSPI_NULL_PATH)
 
         def _state_changed_handler (self,
                                        minor, detail1, detail2, any_data, app,
                                        interface=None, sender=None, member=None, path=None):
                 if interface==_ATSPI_EVENT_OBJECT_INTERFACE:
+                        val = eval("int(state.STATE_" + string.upper(minor) + ")")
+                        high = int(val / 32)
+                        low = val % 32
                         if (sender, path) in self._cache:
                                 item = self._cache[(sender, path)]
-                                val = eval("int(state.STATE_" + string.upper(minor) + ")")
-                                high = int(val / 32)
-                                low = val % 32
                                 if (detail1 == 1):
                                         item.state[high] |= (1 << low)
                                 else:
                                         item.state[high] &= ~(1 << low)
 
+                        if (sender, path) in self._cache.soft:
+                                item = self._cache.soft[(sender, path)]
+                                if "state" in item:
+                                        if (detail1 == 1):
+                                                item["state"][high] |= (1 << low)
+                                        else:
+                                                item["state"][high] &= ~(1 << low)
+
         def remove_all (self):
                 for bus_name, object_path in self._cache.keys():
                         if bus_name == self._bus_name:
@@ -325,6 +350,8 @@ class AccessibleCache (dict):
                 else:
                         self._manager = DesktopCacheManager (self)
 
+                self.soft = weakref.WeakValueDictionary()
+
         def __call__ (self, bus_name, object_path):
                 return self[(bus_name, object_path)]
 



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