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.
16 from dbus.proxies import Interface as _Interface
18 from dbus.exceptions import *
19 from factory import create_accessible, add_accessible_class
23 class AccessibleObjectNoLongerExists(Exception):
26 #------------------------------------------------------------------------------
30 return self._enum_lookup(int(self))
32 #------------------------------------------------------------------------------
35 class _BaseProxyMeta(type):
36 def __init__(cls, *args, **kwargs):
37 type.__init__(cls, *args, **kwargs)
39 queryable_interfaces = {
40 'Accessible':constants.ATSPI_ACCESSIBLE,
41 'Action':constants.ATSPI_ACTION,
42 'Application':constants.ATSPI_APPLICATION,
43 'Collection':constants.ATSPI_COLLECTION,
44 'Component':constants.ATSPI_COMPONENT,
45 'Desktop':constants.ATSPI_DESKTOP,
46 'Document':constants.ATSPI_DOCUMENT,
47 'EditableText':constants.ATSPI_EDITABLE_TEXT,
48 'Hypertext':constants.ATSPI_HYPERTEXT,
49 'Hyperlink':constants.ATSPI_HYPERLINK,
50 'Image':constants.ATSPI_IMAGE,
51 'Selection':constants.ATSPI_SELECTION,
52 'StreamableContent':constants.ATSPI_STREAMABLE_CONTENT,
53 'Table':constants.ATSPI_TABLE,
54 'Text':constants.ATSPI_TEXT,
55 'Value':constants.ATSPI_VALUE,
58 for interface in queryable_interfaces.keys():
59 name = 'query%s' % interface
60 def new_query(self, object):
61 return self.queryInterface(object, queryable_interfaces[interface])
62 setattr(cls, name, new_query)
64 #------------------------------------------------------------------------------
66 class _BaseProxy(_Interface):
68 The base D-Bus proxy for a remote object that implements one or more
69 of the AT-SPI interfaces.
72 __metaclass__ = _BaseProxyMeta
74 def __init__(self, cache, app_name, acc_path, parent, interface, dbus_object=None, connection=None):
76 Create a D-Bus Proxy for an ATSPI interface.
78 cache - ApplicationCache, where the cached data for the accessible can be obtained.
79 app_name - D-Bus bus name of the application this accessible belongs to.
80 acc_path - D-Bus object path of the server side accessible object.
81 parent - Parent accessible.
82 interface - D-Bus interface of the object. Used to decide which accessible class to instanciate.
83 dbus_object(kwarg) - The D-Bus proxy object used by the accessible for D-Bus method calls.
86 self._app_name = app_name
87 self._acc_path = acc_path
91 dbus_object = connection.get_object(self._app_name, self._acc_path, introspect=False)
92 self._dbus_object = dbus_object
94 _Interface.__init__(self, self._dbus_object, interface)
96 self._pgetter = self.get_dbus_method("Get", dbus_interface="org.freedesktop.DBus.Properties")
97 self._psetter = self.get_dbus_method("Set", dbus_interface="org.freedesktop.DBus.Properties")
99 def __getattr__(self, *args, **kwargs):
100 method = _Interface.__getattr__(self, *args, **kwargs)
102 def dbus_method_func(*args, **kwargs):
103 # TODO Need to throw an AccessibleObjectNoLongerExists exception
104 # on D-Bus error of the same type.
106 method(*args, **kwargs)
107 except UnknownMethodException, e:
108 raise NotImplementedError(e)
109 except DBusException, e:
112 return dbus_method_func
115 def cached_data(self):
117 return self._cache[self._app_name][self._acc_path]
119 raise AccessibleObjectNoLongerExists, \
120 'Cache data cannot be found for path %s in app %s' % (self._acc_path, self._app_name)
123 def interfaces(self):
124 return self._data.interfaces
126 def queryInterface(self, interface):
128 Gets a different accessible interface for this object
129 or raises a NotImplemented error if the given interface
132 if interface in self._data.interfaces:
133 return create_accessible(self._cache,
138 dbus_object=self._dbus_object)
140 raise NotImplementedError(
141 "%s not supported by accessible object at path %s"
142 % (interface, self.path))
144 #------------------------------------------------------------------------------
146 class Accessible(_BaseProxy):
148 The base interface which is implemented by all accessible objects.
149 All objects support interfaces for querying their contained
150 'children' and position in the accessible-object hierarchy,
151 whether or not they actually have children.
154 def getApplication(self):
156 Get the containing Application for this object.
157 @return the Application instance to which this object belongs.
159 application_root = self._cache.get_application_root(self._app_name)
160 return create_accessible(self._cache,
163 constants.NULL_BUS_NAME,
164 constants.NULL_OBJECT_PATH,
165 constants.ATSPI_ACCESSIBLE,
166 dbus_object=self._dbus_object)
168 def getAttributes(self, *args, **kwargs):
170 Get a list of properties applied to this object as a whole, as
171 an AttributeSet consisting of name-value pairs. As such these
172 attributes may be considered weakly-typed properties or annotations,
173 as distinct from the strongly-typed interface instance data declared
174 using the IDL "attribute" keyword.
175 Not all objects have explicit "name-value pair" AttributeSet
177 Attribute names and values may have any UTF-8 string value, however
178 where possible, in order to facilitate consistent use and exposure
179 of "attribute" properties by applications and AT clients, attribute
180 names and values should chosen from a publicly-specified namespace
182 Where possible, the names and values in the name-value pairs
183 should be chosen from well-established attribute namespaces using
184 standard semantics. For example, attributes of Accessible objects
185 corresponding to XHTML content elements should correspond to
186 attribute names and values specified in the w3c XHTML specification,
187 at http://www.w3.org/TR/xhtml2, where such values are not already
188 exposed via a more strongly-typed aspect of the AT-SPI API. Metadata
189 names and values should be chosen from the 'Dublin Core' Metadata
190 namespace using Dublin Core semantics: http://dublincore.org/dcregistry/
191 Similarly, relevant structural metadata should be exposed using
192 attribute names and values chosen from the CSS2 and WICD specification:
193 http://www.w3.org/TR/1998/REC-CSS2-19980512 WICD (http://www.w3.org/TR/2005/WD-WICD-20051121/).
194 @return : an AttributeSet encapsulating any "attribute values"
195 currently defined for the object.
197 func = self.get_dbus_method("getAttributes")
198 return func(*args, **kwargs)
200 def getChildAtIndex(self, index):
202 Get the accessible child of this object at index.
204 an in parameter indicating which child is requested (zero-indexed).
205 @return : the 'nth' Accessible child of this object.
207 path = self.cached_data.children[index]
208 return create_accessible(self._cache,
212 constants.ATSPI_ACCESSIBLE,
213 dbus_object=self._dbus_object)
215 def getIndexInParent(self, *args, **kwargs):
217 Get the index of this object in its parent's child list.
218 @return : a long integer indicating this object's index in the
221 func = self.get_dbus_method("getIndexInParent")
222 return func(*args, **kwargs)
224 def getLocalizedRoleName(self, *args, **kwargs):
226 Get a string indicating the type of UI role played by this object,
227 translated to the current locale.
228 @return : a UTF-8 string indicating the type of UI role played
231 func = self.get_dbus_method("getLocalizedRoleName")
232 return func(*args, **kwargs)
234 def getRelationSet(self, *args, **kwargs):
236 Get a set defining this object's relationship to other accessible
238 @return : a RelationSet defining this object's relationships.
240 func = self.get_dbus_method("getRelationSet")
241 return func(*args, **kwargs)
245 Get the Role indicating the type of UI role played by this object.
246 @return : a Role indicating the type of UI role played by this
249 return self.cached_data.role
251 def getRoleName(self, *args, **kwargs):
253 Get a string indicating the type of UI role played by this object.
254 @return : a UTF-8 string indicating the type of UI role played
257 func = self.get_dbus_method("getRoleName")
258 return func(*args, **kwargs)
260 def getState(self, *args, **kwargs):
262 Get the current state of the object as a StateSet.
263 @return : a StateSet encapsulating the currently true states
266 func = self.get_dbus_method("getState")
267 return func(*args, **kwargs)
269 def isEqual(self, accessible):
271 Determine whether an Accessible refers to the same object as
272 another. This method should be used rather than brute-force comparison
273 of object references (i.e. "by-value" comparison), as two object
274 references may have different apparent values yet refer to the
277 an Accessible object reference to compare to
278 @return : a boolean indicating whether the two object references
279 point to the same object.
281 return (self._app_name == accessible._app_name) and \
282 (self._acc_path == accessible._acc_path)
284 def unimplemented(self, *args, **kwargs):
286 /cond future expansion
288 func = self.get_dbus_method("unimplemented")
289 return func(*args, **kwargs)
291 def get_childCount(self):
292 return len(self.cached_data.children)
295 childCount: the number of children contained by this object.
297 childCount = property(fget=get_childCount, doc=_childCountDoc)
299 def get_description(self):
300 return self.cached_data.description
303 a string describing the object in more detail than name.
305 description = property(fget=get_description, doc=_descriptionDoc)
308 return self.cached_data.name
311 a (short) string representing the object's name.
313 name = property(fget=get_name, doc=_nameDoc)
315 def get_parent(self):
316 # The parent attribute is part of the base proxy
320 an Accessible object which is this object's containing object.
322 parent = property(fget=get_parent, doc=_parentDoc)
324 # ATTENTION - Register the Accessible class with the accessible factory.
325 add_accessible_class(constants.ATSPI_ACCESSIBLE, Accessible)
327 #END----------------------------------------------------------------------------