summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Doffman <mdoff@silver-wind.(none)>2009-06-09 11:30:13 +0100
committerMark Doffman <mdoff@silver-wind.(none)>2009-06-09 11:30:13 +0100
commita0c063906bb833e8151ff24f6e50d21f6396e83c (patch)
tree161fa4f6014cde621a80ad0834e51f89969e005a
parent56af2f471b3c7c39fb47d94ee4f39d1c18acc419 (diff)
downloadat-spi2-atk-a0c063906bb833e8151ff24f6e50d21f6396e83c.tar.gz
Refactor the application cache to send signals
when the cache is updated.
-rw-r--r--pyatspi/applicationcache.py158
1 files changed, 156 insertions, 2 deletions
diff --git a/pyatspi/applicationcache.py b/pyatspi/applicationcache.py
index 2eeb27b..a631e84 100644
--- a/pyatspi/applicationcache.py
+++ b/pyatspi/applicationcache.py
@@ -111,6 +111,156 @@ class TestApplicationCache(object):
#------------------------------------------------------------------------------
+def _list_items_added_removed (l1, l2):
+ """
+ Returns a tuple (boolean, boolean).
+ The first value indicates if, when
+ moving from l1 to l2, any items have been added.
+ The second value indicates whether any items have
+ been removed.
+ """
+ l1notl2 = [item for item in l1 if item not in l2]
+ l2notl1 = [item for item in l2 if item not in l1]
+ return ((len(l1notl2) > 0), (len(l2notl1) > 0))
+
+#------------------------------------------------------------------------------
+
+class AccessibleCache(object):
+ """
+ There is one accessible cache per application.
+ For each application the accessible cache stores
+ data on every accessible object within the app.
+
+ It also acts as the factory for creating client
+ side proxies for these accessible objects.
+
+ connection - DBus connection.
+ busName - Name of DBus connection where cache interface resides.
+ """
+
+ _PATH = '/org/freedesktop/atspi/tree'
+ _INTERFACE = 'org.freedesktop.atspi.Tree'
+ _GET_METHOD = 'getTree'
+ _UPDATE_SIGNAL = 'updateAccessible'
+ _REMOVE_SIGNAL = 'removeAccessible'
+
+ def __init__(self, registry, connection, bus_name):
+ """
+ Creates a cache.
+
+ connection - DBus connection.
+ busName - Name of DBus connection where cache interface resides.
+ """
+ self._registry = registry
+ self._connection = connection
+ self._bus_name = bus_name
+
+ obj = connection.get_object(bus_name, self._PATH, introspect=False)
+ self._tree_itf = _dbus.Interface(obj, self._INTERFACE)
+
+ self._objects = {}
+
+ get_method = self._tree_itf.get_dbus_method(self._GET_METHOD)
+ self._update_objects(get_method())
+
+ self._updateMatch = self._tree_itf.connect_to_signal(self._UPDATE_SIGNAL, self._update_single)
+ self._removeMatch = self._tree_itf.connect_to_signal(self._REMOVE_SIGNAL, self._remove_object)
+
+ self._root = self._tree_itf.getRoot()
+
+ def __getitem__(self, key):
+ return self._objects[key]
+
+ def __contains__(self, key):
+ return key in self._objects
+
+ def _dispatch_event(self, olddata, newdata):
+ if olddata.name != newdata.name:
+ event = _Event(self._registry.cache,
+ newdata.path,
+ self._bus_name,
+ "org.freedesktop.atspi.Event.Object",
+ "property-change",
+ ("accessible-name", 0, 0, newdata.name))
+ self._registry._notifyNameChange(event)
+
+ if olddata.description != newdata.description:
+ event = _Event(self._registry.cache,
+ newdata.path,
+ self._bus_name,
+ "org.freedesktop.atspi.Event.Object",
+ "property-change",
+ ("accessible-description", 0, 0, newdata.description))
+ self._registry._notifyDescriptionChange(event)
+
+ if olddata.parent != newdata.parent:
+ event = _Event(self._registry.cache,
+ newdata.path,
+ self._bus_name,
+ "org.freedesktop.atspi.Event.Object",
+ "property-change",
+ ("accessible-parent", 0, 0, ""))
+ self._registry._notifyParentChange(event)
+
+ removed, added = _list_items_added_removed (olddata.children, newdata.children)
+
+ if added:
+ event = _Event(self._registry.cache,
+ newdata.path,
+ self._bus_name,
+ "org.freedesktop.atspi.Event.Object",
+ "children-changed",
+ ("add", 0, 0, ""))
+ self._registry._notifyChildrenChange(event)
+
+ if removed:
+ event = _Event(self._registry.cache,
+ newdata.path,
+ self._bus_name,
+ "org.freedesktop.atspi.Event.Object",
+ "children-changed",
+ ("remove", 0, 0, ""))
+ self._registry._notifyChildrenChange(event)
+
+ # TODO This should be the other way around. Single is more common than many.
+ def _update_single(self, object):
+ self._update_objects ([object])
+
+ def _update_objects(self, objects):
+ cache_update_objects = []
+ for data in objects:
+ #First element is the object path.
+ path = data[0]
+ if path in self._objects:
+ olddata = self._objects[path]
+ newdata = _CacheData(data)
+ cache_update_objects.append((olddata, newdata))
+ self._objects[path] = newdata
+ else:
+ self._objects[path] = _CacheData(data)
+ for old, new in cache_update_objects:
+ self._dispatch_event(old, new)
+
+ def _remove_object(self, path):
+ # TODO I'm squashing a possible error here
+ # I've seen things appear to be deleted twice
+ # which needs investigation
+ try:
+ del(self._objects[path])
+ except KeyError:
+ pass
+
+ def _get_root(self):
+ return self._root
+
+ def _refresh(self):
+ get_method = self._tree_itf.get_dbus_method(self._GET_METHOD)
+ self._update_objects(get_method())
+
+ root = property(fget=_get_root)
+
+#END---------------------------------------------------------------------------
+
class ApplicationCache(object):
"""
Test application store, accesses a single application.
@@ -234,7 +384,11 @@ class ApplicationCache(object):
return self._connection
def _refresh(self):
- self.application_list = []
- self.application_list.extend(self._app_register.getApplications())
+ app_addresses = self._app_register.getApplications()
+ added, removed = _list_items_added_removed (self.application_list, app_addresses)
+ for item in added:
+ self.update_handler (ApplicationsCache._APPLICATIONS_ADD, item):
+ for item in removed:
+ self.update_handler (ApplicationsCache._APPLICATIONS_REMOVE, item):
#END----------------------------------------------------------------------------