1 #Copyright (C) 2008 Codethink Ltd
3 #This library is free software; you can redistribute it and/or
4 #modify it under the terms of the GNU Lesser General Public
5 #License version 2 as published by the Free Software Foundation.
7 #This program is distributed in the hope that it will be useful,
8 #but WITHOUT ANY WARRANTY; without even the implied warranty of
9 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 #GNU General Public License for more details.
11 #You should have received a copy of the GNU Lesser General Public License
12 #along with this program; if not, write to the Free Software
13 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 from event import Event as _Event
19 #------------------------------------------------------------------------------
21 class _CacheData(object):
33 def __init__(self, data):
36 def _update(self, data):
46 #------------------------------------------------------------------------------
48 def _list_items_added_removed (l1, l2):
50 Returns a tuple (boolean, boolean).
51 The first value indicates if, when
52 moving from l1 to l2, any items have been added.
53 The second value indicates whether any items have
56 l1notl2 = [item for item in l1 if item not in l2]
57 l2notl1 = [item for item in l2 if item not in l1]
58 return ((len(l1notl2) > 0), (len(l2notl1) > 0))
60 #------------------------------------------------------------------------------
62 class AccessibleCache(object):
64 There is one accessible cache per application.
65 For each application the accessible cache stores
66 data on every accessible object within the app.
68 It also acts as the factory for creating client
69 side proxies for these accessible objects.
71 connection - DBus connection.
72 busName - Name of DBus connection where cache interface resides.
75 _PATH = '/org/freedesktop/atspi/tree'
76 _INTERFACE = 'org.freedesktop.atspi.Tree'
77 _GET_METHOD = 'getTree'
78 _UPDATE_SIGNAL = 'updateAccessible'
79 _REMOVE_SIGNAL = 'removeAccessible'
81 def __init__(self, registry, connection, bus_name):
85 connection - DBus connection.
86 busName - Name of DBus connection where cache interface resides.
88 self._registry = registry
89 self._connection = connection
90 self._bus_name = bus_name
92 obj = connection.get_object(bus_name, self._PATH, introspect=False)
93 itf = _dbus.Interface(obj, self._INTERFACE)
97 get_method = itf.get_dbus_method(self._GET_METHOD)
98 self._update_objects(get_method())
100 self._updateMatch = itf.connect_to_signal(self._UPDATE_SIGNAL, self._update_single)
101 self._removeMatch = itf.connect_to_signal(self._REMOVE_SIGNAL, self._remove_object)
103 obj = connection.get_object(self._bus_name, self._PATH, introspect=False)
104 itf = _dbus.Interface(obj, self._INTERFACE)
106 self._root = itf.getRoot()
108 def __getitem__(self, key):
109 return self._objects[key]
111 def __contains__(self, key):
112 return key in self._objects
114 def _dispatch_event(self, olddata, newdata):
115 if olddata.name != newdata.name:
116 event = _Event(self._registry.cache,
119 "org.freedesktop.atspi.Event.Object",
121 ("accessible-name", 0, 0, newdata.name))
122 self._registry._notifyNameChange(event)
124 if olddata.description != newdata.description:
125 event = _Event(self._registry.cache,
128 "org.freedesktop.atspi.Event.Object",
130 ("accessible-description", 0, 0, description))
131 self._registry._notifyDescriptionChange(event)
133 if olddata.parent != newdata.parent:
134 event = _Event(self._registry.cache,
137 "org.freedesktop.atspi.Event.Object",
139 ("accessible-parent", 0, 0, ""))
140 self._registry._notifyParentChange(event)
142 removed, added = _list_items_added_removed (olddata.children, newdata.children)
145 event = _Event(self._registry.cache,
148 "org.freedesktop.atspi.Event.Object",
151 self._registry._notifyChildrenChange(event)
154 event = _Event(self._registry.cache,
157 "org.freedesktop.atspi.Event.Object",
159 ("remove", 0, 0, ""))
160 self._registry._notifyChildrenChange(event)
162 # TODO This should be the other way around. Single is more common than many.
163 def _update_single(self, object):
164 self._update_objects ([object])
166 def _update_objects(self, objects):
167 cache_update_objects = []
169 #First element is the object path.
171 if path in self._objects:
172 olddata = self._objects[path]
173 newdata = _CacheData(data)
174 cache_update_objects.append((olddata, newdata))
175 self._objects[path] = newdata
177 self._objects[path] = _CacheData(data)
178 for old, new in cache_update_objects:
179 self._dispatch_event(old, new)
181 def _remove_object(self, paths):
182 # TODO I'm squashing a possible error here
183 # I've seen things appear to be deleted twice
184 # which needs investigation
186 del(self._objects[path])
193 root = property(fget=_get_root)
195 #END---------------------------------------------------------------------------