2008-09-08 Mark Doffman <mark.doffman@codethink.co.uk>
authorMark Doffman <mdoff@silver-wind.(none)>
Mon, 8 Sep 2008 08:40:42 +0000 (09:40 +0100)
committerMark Doffman <mdoff@silver-wind.(none)>
Mon, 8 Sep 2008 08:40:42 +0000 (09:40 +0100)
* pyatspi/Accessibility.py
Add all interfaces to Accessibility module before importing
to pyatspi. This is to keep compatibility with ORBit pyatspi.

* pyatspi/*.py
Fix error where properties did not properly return a value.

* atk-adaptor/text.c
Fix error in marshalling getAttributes method.

* atk-adaptor/tree.c
Fix error in marshalling interfaces of tree of accessibles

22 files changed:
atk-adaptor/text.c
atk-adaptor/tree.c
pyatspi/Accessibility.py [new file with mode: 0644]
pyatspi/__init__.py
pyatspi/accessible.py
pyatspi/application.py
pyatspi/base.py
pyatspi/cache.py
pyatspi/constants.py
pyatspi/desktop.py
pyatspi/event.py
pyatspi/hyperlink.py
pyatspi/image.py
pyatspi/registry.py
pyatspi/selection.py
pyatspi/selector.py
pyatspi/streamablecontent.py
pyatspi/table.py
pyatspi/test.py
pyatspi/text.py
pyatspi/utils.py
pyatspi/value.py

index c22b0ea..451a92b 100644 (file)
@@ -375,18 +375,19 @@ impl_getAttributes (DBusConnection * bus, DBusMessage * message,
 
   set = atk_text_get_run_attributes (text, offset,
                                     &intstart_offset, &intend_offset);
+
+  rv = _string_from_attribute_set (set);
+
   startOffset = intstart_offset;
   endOffset = intend_offset;
-  rv = _string_from_attribute_set (set);
   reply = dbus_message_new_method_return (message);
   if (reply)
     {
-      dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
-                               DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_STRING,
-                               &rv, DBUS_TYPE_INVALID);
+      dbus_message_append_args (reply, DBUS_TYPE_STRING, &rv, DBUS_TYPE_INT32, &startOffset,
+                               DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_INVALID);
     }
-  g_free (rv);
   atk_attribute_set_free (set);
+  g_free(rv);
   return reply;
 }
 
index 7efca21..00ec003 100644 (file)
@@ -67,7 +67,6 @@ append_accessible(gpointer ref, gpointer obj_data, gpointer iter)
 
       path = atk_dbus_get_path_from_ref(GPOINTER_TO_INT(ref));
       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
-      g_free(path);
 
       parent = atk_object_get_parent(obj);
       if (parent == NULL)
@@ -128,6 +127,8 @@ append_accessible(gpointer ref, gpointer obj_data, gpointer iter)
       if (!desc)
         desc = "";
       dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &desc);
+
+      g_free(path);
     }      
   dbus_message_iter_close_container (iter_array, &iter_struct);
 }
diff --git a/pyatspi/Accessibility.py b/pyatspi/Accessibility.py
new file mode 100644 (file)
index 0000000..526b71f
--- /dev/null
@@ -0,0 +1,42 @@
+#Copyright (C) 2008 Codethink Ltd
+
+#This library is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public
+#License version 2 as published by the Free Software Foundation.
+
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#You should have received a copy of the GNU Lesser General Public License
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+from constants import *
+
+from registry import*
+from accessible import *
+from action import *
+from application import *
+from collection import *
+from component import *
+from constants import *
+from desktop import *
+from document import *
+from editabletext import *
+from hyperlink import *
+from hypertext import *
+from image import *
+from interfaces import *
+from loginhelper import *
+from relation import *
+from role import *
+from selection import *
+from selector import *
+from state import *
+from streamablecontent import *
+from table import *
+from test import *
+from text import *
+from utils import *
+from value import *
index 12be5df..510e65b 100644 (file)
 #along with this program; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
-import registry
-
-#Registry = registry.Registry()
-#registry.Registry = Registry
-#del registry
+__version__ = (1, 9, 0)
 
-from constants import *
-
-from accessible import *
-from action import *
-from application import *
-from collection import *
-from component import *
-from constants import *
-from desktop import *
-from document import *
-from editabletext import *
-from hyperlink import *
-from hypertext import *
-from image import *
-from interfaces import *
-from loginhelper import *
-from relation import *
-from role import *
-from selection import *
-from selector import *
-from state import *
-from streamablecontent import *
-from table import *
-from test import *
-from text import *
-from utils import *
-from value import *
+import registry
+Registry = registry._Registry()
+registry._Registry = Registry
+del registry
 
-#from utils import *
+import constants
+from Accessibility import *
index 86802c5..39584ca 100644 (file)
@@ -92,6 +92,9 @@ class Accessible(BaseProxy):
     whether or not they actually have children.
     """
 
+    def __nonzero__(self):
+           return True
+
     def __len__(self):
            return self.getChildCount()
 
@@ -232,6 +235,7 @@ class Accessible(BaseProxy):
         """
         return  (self._app_name == accessible._app_name) and \
                (self._acc_path == accessible._acc_path)        
+
     
     def get_childCount(self):
         return len(self.cached_data.children)
@@ -240,6 +244,8 @@ class Accessible(BaseProxy):
         childCount: the number of children contained by this object.
         """
     childCount = property(fget=get_childCount, doc=_childCountDoc)
+
+    getChildCount = get_childCount
     
     def get_description(self):
         return self.cached_data.description
index c0c8284..12abe5a 100644 (file)
@@ -90,7 +90,7 @@ class Application(Accessible):
         return func(*args, **kwargs)
     
     def get_id(self):
-        self._pgetter(self._dbus_interface, "id")
+        return self._pgetter(self._dbus_interface, "id")
     def set_id(self, value):
         self._psetter(self._dbus_interface, "id", value)
     _idDoc = \
@@ -100,7 +100,7 @@ class Application(Accessible):
     id = property(fget=get_id, fset=set_id, doc=_idDoc)
     
     def get_toolkitName(self):
-        self._pgetter(self._dbus_interface, "toolkitName")
+        return self._pgetter(self._dbus_interface, "toolkitName")
     def set_toolkitName(self, value):
         self._psetter(self._dbus_interface, "toolkitName", value)
     _toolkitNameDoc = \
@@ -111,7 +111,7 @@ class Application(Accessible):
     toolkitName = property(fget=get_toolkitName, fset=set_toolkitName, doc=_toolkitNameDoc)
     
     def get_version(self):
-        self._pgetter(self._dbus_interface, "version")
+        return self._pgetter(self._dbus_interface, "version")
     def set_version(self, value):
         self._psetter(self._dbus_interface, "version", value)
     _versionDoc = \
index 4fabeec..c950ec8 100644 (file)
@@ -157,6 +157,6 @@ class BaseProxy(Interface):
                else:
                        raise NotImplementedError(
                                "%s not supported by accessible object at path %s"
-                               % (interface, self.path))
+                               % (interface, self._acc_path))
 
 #END----------------------------------------------------------------------------
index 56ab0f6..e744ca5 100644 (file)
@@ -14,6 +14,8 @@
 
 import dbus as _dbus
 
+from event import Event as _Event
+
 #------------------------------------------------------------------------------
 
 class _CacheData(object):
@@ -27,9 +29,9 @@ class _CacheData(object):
                        ]
 
        def __init__(self, data):
-               self.update(data)
+               self._update(data)
 
-       def update(self, data):
+       def _update(self, data):
                #Don't cache the path here, used as lookup in cache object dict.
                (path,
                self.parent,
@@ -41,15 +43,32 @@ class _CacheData(object):
 
 #------------------------------------------------------------------------------
 
-class _BaseCache(object):
+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 = 'updateTree'
 
-       def __init__(self, connection, bus_name):
+       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
 
@@ -63,12 +82,67 @@ class _BaseCache(object):
 
                self._signalMatch = itf.connect_to_signal(self._UPDATE_SIGNAL, self._update_handler)
 
+               obj = connection.get_object(self._bus_name, self._PATH, introspect=False)
+               itf = _dbus.Interface(obj, self._INTERFACE)
+
+               self._root = itf.getRoot()
+
        def __getitem__(self, key):
                return self._objects[key]
 
        def __contains__(self, key):
                return key in self._objects
 
+       def _update_cache_dispatch_events(self, cachedata, data):
+               (path,
+                parent,
+                children,
+                interfaces,
+                name,
+                role,
+                description) = data
+               
+               # TODO The 'self._registry._cache' statement makes me think
+               # I have serious modularization FAIL here. 
+
+               if name != cachedata.name:
+                       event = _Event(self._registry._cache,
+                                      path,
+                                      self._bus_name,
+                                      "org.freedesktop.atspi.Event.Object",
+                                      "property-change",
+                                      ("name", 0, 0, name))
+                       self._registry._notifyNameChange(event)
+
+               if description != cachedata.description:
+                       event = _Event(self._registry._cache,
+                                      path,
+                                      self._bus_name,
+                                      "org.freedesktop.atspi.Event.Object",
+                                      "property-change",
+                                      ("description", 0, 0, description))
+                       self._registry._notifyDescriptionChange(event)
+
+               if parent != cachedata.parent:
+                       event = _Event(self._registry._cache,
+                                      path,
+                                      self._bus_name,
+                                      "org.freedesktop.atspi.Event.Object",
+                                      "property-change",
+                                      ("parent", 0, 0, ""))
+                       self._registry._notifyParentChange(event)
+
+               if children != cachedata.children:
+                       event = _Event(self._registry._cache,
+                                      path,
+                                      self._bus_name,
+                                      "org.freedesktop.atspi.Event.Object",
+                                      "children-changed",
+                                      ("", 0, 0, ""))
+                       self._registry._notifyChildrenChange(event)
+
+               cachedata._update(data)
+
        def _update_handler(self, update, remove):
                self._remove_objects(remove)
                self._update_objects(update)
@@ -79,47 +153,23 @@ class _BaseCache(object):
                        path = data[0]
                        if path in self._objects:
                                cachedata = self._objects[path]
-                               cachedata.update(data)
+                               self._update_cache_dispatch_events(cachedata, data)
                        else:
                                self._objects[path] = _CacheData(data)
 
        def _remove_objects(self, paths):
                for path in paths:
-                       del(self._objects[path])
-
-
-#------------------------------------------------------------------------------
-
-class AccessibleCache(_BaseCache):
-       """
-       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 = 'updateTree'
-
-       def __init__(self, connection, bus_name):
-               _BaseCache.__init__(self, connection, bus_name)
-
-               obj = connection.get_object(self._bus_name, self._PATH, introspect=False)
-               itf = _dbus.Interface(obj, self._INTERFACE)
-
-               self._root = itf.getRoot()
+                       # 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
 
        root = property(fget=_get_root)
 
-
 #END---------------------------------------------------------------------------
index db3b971..006723c 100644 (file)
@@ -138,3 +138,5 @@ EVENT_TREE = {
   'focus' :
     ['focus:']
 }
+
+from Accessibility import *
index 37898c2..1cbf1e8 100644 (file)
@@ -189,6 +189,9 @@ class Desktop(object):
        self._cache = cache
        self._app_name = '/'
 
+    def __nonzero__(self):
+           return True
+
     def __len__(self):
            return self.getChildCount()
 
@@ -242,7 +245,7 @@ class Desktop(object):
         an in parameter indicating which child is requested (zero-indexed).
         @return : the 'nth' Accessible child of this object.
         """
-       return self._cache.get_application_at_index(index)
+       return self._cache.get_application_at_index(index, self)
     
     def getIndexInParent(self):
         """
@@ -307,7 +310,7 @@ class Desktop(object):
         point to the same object.
         """
         return self == accessible
-    
+
     def get_childCount(self):
         return self._cache.get_application_count()
     _childCountDoc = \
@@ -315,6 +318,8 @@ class Desktop(object):
         childCount: the number of children contained by this object.
         """
     childCount = property(fget=get_childCount, doc=_childCountDoc)
+
+    getChildCount = get_childCount
     
     def get_description(self):
         return ''
@@ -340,6 +345,10 @@ class Desktop(object):
         """
     parent = property(fget=get_parent, doc=_parentDoc)
 
+    @property
+    def interfaces(self):
+        return [interfaces.ATSPI_ACCESSIBLE, interfaces.ATSPI_COMPONENT]
+
     def queryInterface(self, interface):
        """
        Gets a different accessible interface for this object
index c7ef618..4ae61ee 100644 (file)
@@ -128,10 +128,12 @@ def event_type_to_signal_reciever(bus, cache, event_handler, event_type):
                        'member_keyword':'member',
                        'path_keyword':'path',
                 }
+       if event_type.major:
+               major = event_type.major.replace('-', '_')
        if event_type.klass:
                kwargs['dbus_interface'] = _klass_to_interface[event_type.klass]
        if event_type.major:
-               kwargs['signal_name'] = event_type.major
+               kwargs['signal_name'] = major
        if event_type.minor:
                kwargs['arg0'] = event_type.minor
 
index 96f7141..01afd4e 100644 (file)
@@ -73,7 +73,7 @@ class Hyperlink(BaseProxy):
         return func(*args, **kwargs)
     
     def get_endIndex(self):
-        self._pgetter(self._dbus_interface, "endIndex")
+        return self._pgetter(self._dbus_interface, "endIndex")
     def set_endIndex(self, value):
         self._psetter(self._dbus_interface, "endIndex", value)
     _endIndexDoc = \
@@ -86,7 +86,7 @@ class Hyperlink(BaseProxy):
     endIndex = property(fget=get_endIndex, fset=set_endIndex, doc=_endIndexDoc)
     
     def get_nAnchors(self):
-        self._pgetter(self._dbus_interface, "nAnchors")
+        return self._pgetter(self._dbus_interface, "nAnchors")
     def set_nAnchors(self, value):
         self._psetter(self._dbus_interface, "nAnchors", value)
     _nAnchorsDoc = \
@@ -96,7 +96,7 @@ class Hyperlink(BaseProxy):
     nAnchors = property(fget=get_nAnchors, fset=set_nAnchors, doc=_nAnchorsDoc)
     
     def get_startIndex(self):
-        self._pgetter(self._dbus_interface, "startIndex")
+        return self._pgetter(self._dbus_interface, "startIndex")
     def set_startIndex(self, value):
         self._psetter(self._dbus_interface, "startIndex", value)
     _startIndexDoc = \
index 0190bb3..bf9beb5 100644 (file)
 #along with this program; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
+import dbus
 import interfaces
 from base import BaseProxy
 from factory import add_accessible_class
+from accessible import BoundingBox
 
 __all__ = [
           "Image",
@@ -34,7 +36,7 @@ class Image(BaseProxy):
     well as the Accessible::name and Accessible::description properties.
     """
     
-    def getImageExtents(self, *args, **kwargs):
+    def getImageExtents(self, coordType):
         """
         Obtain a bounding box which entirely contains the image contents,
         as displayed on screen. The bounds returned do not account for
@@ -47,7 +49,7 @@ class Image(BaseProxy):
         @return a BoundingBox enclosing the image's onscreen representation.
         """
         func = self.get_dbus_method("getImageExtents")
-        return func(*args, **kwargs)
+        return BoundingBox(*func(dbus.Int16(coordType)))
     
     def getImagePosition(self, *args, **kwargs):
         """
@@ -83,7 +85,7 @@ class Image(BaseProxy):
         return func(*args, **kwargs)
 
     def get_imageDescription(self):
-        self._pgetter(self._dbus_interface, "imageDescription")
+        return self._pgetter(self._dbus_interface, "imageDescription")
     def set_imageDescription(self, value):
         self._psetter(self._dbus_interface, "imageDescription", value)
     _imageDescriptionDoc = \
@@ -94,7 +96,7 @@ class Image(BaseProxy):
     imageDescription = property(fget=get_imageDescription, fset=set_imageDescription, doc=_imageDescriptionDoc)
     
     def get_imageLocale(self):
-        self._pgetter(self._dbus_interface, "imageLocale")
+        return self._pgetter(self._dbus_interface, "imageLocale")
     def set_imageLocale(self, value):
         self._psetter(self._dbus_interface, "imageLocale", value)
     _imageLocaleDoc = \
index 164fa49..96c3d10 100644 (file)
 
 #authors: Peter Parente, Mark Doffman
 
-import dbus
-import gobject
+import os as _os
+import dbus as _dbus
+import gobject as _gobject
 
-from dbus.mainloop.glib import DBusGMainLoop
-DBusGMainLoop(set_as_default=True)
+from base import Enum as _Enum
+from desktop import Desktop as _Desktop
+from event import EventType as _EventType
+from event import event_type_to_signal_reciever as _event_type_to_signal_reciever
+from test import TestApplicationCache as _TestApplicationCache
 
-from test import TestApplicationCache
-from desktop import Desktop
-from event import EventType, event_type_to_signal_reciever
+from dbus.mainloop.glib import DBusGMainLoop as _DBusGMainLoop
+_DBusGMainLoop(set_as_default=True)
 
-class Registry(object):
+#------------------------------------------------------------------------------
+
+class PressedEventType(_Enum):
+    _enum_lookup = {
+        0:'KEY_PRESSED_EVENT',
+        1:'KEY_RELEASED_EVENT',
+        2:'BUTTON_PRESSED_EVENT',
+        3:'BUTTON_RELEASED_EVENT',
+    }
+
+KEY_PRESSED_EVENT = PressedEventType(0)
+KEY_RELEASED_EVENT = PressedEventType(1)
+BUTTON_PRESSED_EVENT = PressedEventType(2)
+BUTTON_RELEASED_EVENT = PressedEventType(3)
+#------------------------------------------------------------------------------
+
+class KeyEventType(_Enum):
+    _enum_lookup = {
+        0:'KEY_PRESSED',
+        1:'KEY_RELEASED',
+    }
+KEY_PRESSED = KeyEventType(0)
+KEY_RELEASED = KeyEventType(1)
+
+#------------------------------------------------------------------------------
+
+class KeySynthType(_Enum):
+    _enum_lookup = {
+        0:'KEY_PRESS',
+        1:'KEY_RELEASE',
+        2:'KEY_PRESSRELEASE',
+        3:'KEY_SYM',
+        4:'KEY_STRING',
+    }
+
+KEY_PRESS = KeySynthType(0)
+KEY_PRESSRELEASE = KeySynthType(2)
+KEY_RELEASE = KeySynthType(1)
+KEY_STRING = KeySynthType(4)
+KEY_SYM = KeySynthType(3)
+
+#------------------------------------------------------------------------------
+
+class ModifierType(_Enum):
+    _enum_lookup = {
+        0:'MODIFIER_SHIFT',
+        1:'MODIFIER_SHIFTLOCK',
+        2:'MODIFIER_CONTROL',
+        3:'MODIFIER_ALT',
+        4:'MODIFIER_META',
+        5:'MODIFIER_META2',
+        6:'MODIFIER_META3',
+        7:'MODIFIER_NUMLOCK',
+    }
+
+MODIFIER_ALT = ModifierType(3)
+MODIFIER_CONTROL = ModifierType(2)
+MODIFIER_META = ModifierType(4)
+MODIFIER_META2 = ModifierType(5)
+MODIFIER_META3 = ModifierType(6)
+MODIFIER_NUMLOCK = ModifierType(7)
+MODIFIER_SHIFT = ModifierType(0)
+MODIFIER_SHIFTLOCK = ModifierType(1)
+
+#------------------------------------------------------------------------------
+
+class _Registry(object):
        """
        Wraps the Accessibility.Registry to provide more Pythonic registration for
        events. 
@@ -56,7 +125,7 @@ class Registry(object):
 
        _REGISTRY_NAME = 'org.freedesktop.atspi.Registry'
 
-       def __init__(self, app_name=None):
+       def __init__(self):
                """
                Stores a reference to the AT-SPI registry. Gets and stores a reference
                to the DeviceEventController.
@@ -64,12 +133,28 @@ class Registry(object):
                @param reg: Reference to the AT-SPI registry daemon
                @type reg: Accessibility.Registry
                """
-               self._bus = dbus.SessionBus()
+               self._bus = _dbus.SessionBus()
+
+               app_name = None
+               if "ATSPI_TEST_APP_NAME" in _os.environ.keys():
+                       app_name = _os.environ["ATSPI_TEST_APP_NAME"]
                if app_name:
                        self._app_name = app_name
-                       self._cache = TestApplicationCache(self._bus, app_name)
+                       self._cache = _TestApplicationCache(self, self._bus, app_name)
 
                self._event_listeners = {}
+
+               # All of this special casing is for the 'faked'
+               # events caused by cache updates.
+
+               self._name_type = _EventType("object:property-change:name")
+               self._name_listeners = {}
+               self._description_type = _EventType("object:property-change:description")
+               self._description_listeners = {}
+               self._parent_type = _EventType("object:property-change:parent")
+               self._parent_listeners = {}
+               self._children_changed_type = _EventType("object:children-changed")
+               self._children_changed_listeners = {}
                
        def __call__(self):
                """
@@ -91,10 +176,9 @@ class Registry(object):
                        Note - No Longer used.
                @type gil: boolean
                """
-               self._loop = gobject.MainLoop()
-               self._loop.run()
+               self._loop = _gobject.MainLoop()
                try:
-                       loop.run()
+                       self._loop.run()
                except KeyboardInterrupt:
                        pass
 
@@ -121,7 +205,62 @@ class Registry(object):
                @return: Desktop reference
                @rtype: Accessibility.Desktop
                """
-               return Desktop(self._cache)
+               return _Desktop(self._cache)
+
+       def _callClients(self, register, event):
+               for client in register.keys():
+                       client(event)
+
+       def _notifyNameChange(self, event):
+               self._callClients(self._name_listeners, event)
+
+       def _notifyDescriptionChange(self, event):
+               self._callClients(self._description_listeners, event)
+
+       def _notifyParentChange(self, event):
+               self._callClients(self._parent_listeners, event)
+
+       def _notifyChildenChange(self, event):
+               self._callClients(self._children_changed_listeners, event)
+
+       def _registerFake(self, type, register, client, *names):
+               """
+               Registers a client from a register of clients
+               for 'Fake' events emitted by the cache.
+               """
+               try:
+                       registered = register[client]
+               except KeyError:
+                       registered = []
+                       register[client] = registered
+               
+               for name in names:
+                       new_type = _EventType(name)
+                       if new_type.is_subtype(type):
+                               registered.append(new_type.name)
+
+       def _deregisterFake(self, type, register, client, *names):
+               """
+               Deregisters a client from a register of clients
+               for 'Fake' events emitted by the cache.
+               """
+               try:
+                       registered = register[client]
+               except KeyError:
+                       return True
+               
+               for name in names:
+                       remove_type = _EventType(name)
+
+                       for i in range(0, len(registered) - 1):
+                               type_name = registered[i]
+                               registered_type = _EventType(type_name)
+
+                               if remove_type.is_subtype(registered_type):
+                                       del(registered[i])
+
+               if registered == []:
+                       del(register[client])
 
        def registerEventListener(self, client, *names):
                """
@@ -150,9 +289,14 @@ class Registry(object):
                        self._event_listeners[client] = registered
 
                for name in names:
-                       new_type = EventType(name)
+                       new_type = _EventType(name)
                        registered.append((new_type.name,
-                                          event_type_to_signal_reciever(self._bus, self._cache, client, new_type)))
+                                          _event_type_to_signal_reciever(self._bus, self._cache, client, new_type)))
+
+               self._registerFake(self._name_type, self._name_listeners, client, *names)
+               self._registerFake(self._description_type, self._description_listeners, client, *names)
+               self._registerFake(self._parent_type, self._parent_listeners, client, *names)
+               self._registerFake(self._children_changed_type, self._children_changed_listeners, client, *names)
 
        def deregisterEventListener(self, client, *names):
                """
@@ -177,16 +321,178 @@ class Registry(object):
                        # Presumably if were trying to deregister a client with
                        # no names then the return type is always true.
                        return True
+
+               missing = False
                
                for name in names:
-                       remove_type = EventType(name)
+                       remove_type = _EventType(name)
 
-                       for i in range(0, len(registered)):
+                       for i in range(0, len(registered) - 1):
                                (type_name, signal_match) = registered[i]
-                               registered_type = EventType(type_name)
+                               registered_type = _EventType(type_name)
+
                                if remove_type.is_subtype(registered_type):
                                        signal_match.remove()
                                        del(registered[i])
+                               else:
+                                       missing = True
 
                if registered == []:
                        del(self._event_listeners[client])
+
+               #TODO Do these account for missing also?
+               self._deregisterFake(self._name_type, self._name_listeners, client, *names)
+               self._deregisterFake(self._description_type, self._description_listeners, client, *names)
+               self._deregisterFake(self._parent_type, self._parent_listeners, client, *names)
+               self._deregisterFake(self._children_changed_type, self._children_changed_listeners, client, *names)
+
+               return missing
+
+       def registerKeystrokeListener(self,
+                                     client,
+                                     key_set=[],
+                                     mask=0,
+                                     kind=(KEY_PRESSED_EVENT, KEY_RELEASED_EVENT),
+                                     synchronous=True,
+                                     preemptive=True,
+                                     global_=False):
+               """
+               Registers a listener for key stroke events.
+               
+               @param client: Callable to be invoked when the event occurs
+               @type client: callable
+               @param key_set: Set of hardware key codes to stop monitoring. Leave empty
+                       to indicate all keys.
+               @type key_set: list of integer
+               @param mask: When the mask is None, the codes in the key_set will be 
+                       monitored only when no modifier is held. When the mask is an 
+                       integer, keys in the key_set will be monitored only when the modifiers in
+                       the mask are held. When the mask is an iterable over more than one 
+                       integer, keys in the key_set will be monitored when any of the modifier
+                       combinations in the set are held.
+               @type mask: integer, iterable, None
+               @param kind: Kind of events to watch, KEY_PRESSED_EVENT or 
+                       KEY_RELEASED_EVENT.
+               @type kind: list
+               @param synchronous: Should the callback notification be synchronous, giving
+                       the client the chance to consume the event?
+               @type synchronous: boolean
+               @param preemptive: Should the callback be allowed to preempt / consume the
+                       event?
+               @type preemptive: boolean
+               @param global_: Should callback occur even if an application not supporting
+                       AT-SPI is in the foreground? (requires xevie)
+               @type global_: boolean
+               """
+               pass
+
+       def deregisterKeystrokeListener(self,
+                                       client,
+                                       key_set=[],
+                                       mask=0,
+                                       kind=(KEY_PRESSED_EVENT, KEY_RELEASED_EVENT)):
+               """
+               Deregisters a listener for key stroke events.
+               
+               @param client: Callable to be invoked when the event occurs
+               @type client: callable
+               @param key_set: Set of hardware key codes to stop monitoring. Leave empty
+                       to indicate all keys.
+               @type key_set: list of integer
+               @param mask: When the mask is None, the codes in the key_set will be 
+                       monitored only when no modifier is held. When the mask is an 
+                       integer, keys in the key_set will be monitored only when the modifiers in
+                       the mask are held. When the mask is an iterable over more than one 
+                       integer, keys in the key_set will be monitored when any of the modifier
+                       combinations in the set are held.
+               @type mask: integer, iterable, None
+               @param kind: Kind of events to stop watching, KEY_PRESSED_EVENT or 
+                       KEY_RELEASED_EVENT.
+               @type kind: list
+               @raise KeyError: When the client isn't already registered for events
+               """
+               pass
+
+       def generateKeyboardEvent(self, keycode, keysym, kind):
+               """
+               Generates a keyboard event. One of the keycode or the keysym parameters
+               should be specified and the other should be None. The kind parameter is 
+               required and should be one of the KEY_PRESS, KEY_RELEASE, KEY_PRESSRELEASE,
+               KEY_SYM, or KEY_STRING.
+               
+               @param keycode: Hardware keycode or None
+               @type keycode: integer
+               @param keysym: Symbolic key string or None
+               @type keysym: string
+               @param kind: Kind of event to synthesize
+               @type kind: integer
+               """
+               pass
+       
+       def generateMouseEvent(self, x, y, name):
+               """
+               Generates a mouse event at the given absolute x and y coordinate. The kind
+               of event generated is specified by the name. For example, MOUSE_B1P 
+               (button 1 press), MOUSE_REL (relative motion), MOUSE_B3D (butten 3 
+               double-click).
+               
+               @param x: Horizontal coordinate, usually left-hand oriented
+               @type x: integer
+               @param y: Vertical coordinate, usually left-hand oriented
+               @type y: integer
+               @param name: Name of the event to generate
+               @type name: string
+               """
+               pass
+               
+       def handleDeviceEvent(self, event, ob):
+               """
+               Dispatches L{event.DeviceEvent}s to registered clients. Clients are called
+               in the order they were registered for the given AT-SPI event. If any
+               client returns True, callbacks cease for the event for clients of this registry 
+               instance. Clients of other registry instances and clients in other processes may 
+               be affected depending on the values of synchronous and preemptive used when invoking
+               L{registerKeystrokeListener}. 
+               
+               @note: Asynchronous dispatch of device events is not supported.
+               
+               @param event: AT-SPI device event
+               @type event: L{event.DeviceEvent}
+               @param ob: Observer that received the event
+               @type ob: L{_DeviceObserver}
+
+               @return: Should the event be consumed (True) or allowed to pass on to other
+                       AT-SPI observers (False)?
+               @rtype: boolean
+               """
+               return True
+       def handleEvent(self, event):
+               """             
+               Handles an AT-SPI event by either queuing it for later dispatch when the
+               L{Registry.async} flag is set, or dispatching it immediately.
+
+               @param event: AT-SPI event
+               @type event: L{event.Event}
+               """
+               pass
+
+       def flushEvents(self):
+               """
+               Flushes the event queue by destroying it and recreating it.
+               """
+               pass
+
+       def pumpQueuedEvents(self, num=-1):
+               """
+               Provides asynch processing of events in the queue by executeing them with 
+               _dispatchEvent() (as is done immediately when synch processing). 
+               This method would normally be called from a main loop or idle function.
+
+               @param num: Number of events to pump. If number is negative it pumps
+               the entire queue. Default is -1.
+               @type num: integer
+               @return: True if queue is not empty after events were pumped.
+               @rtype: boolean
+               """
+               return False
index 8e690b5..3811061 100644 (file)
@@ -119,7 +119,7 @@ class Selection(BaseProxy):
         return func(*args, **kwargs)
     
     def get_nSelectedChildren(self):
-        self._pgetter(self._dbus_interface, "nSelectedChildren")
+        return self._pgetter(self._dbus_interface, "nSelectedChildren")
     def set_nSelectedChildren(self, value):
         self._psetter(self._dbus_interface, "nSelectedChildren", value)
     _nSelectedChildrenDoc = \
index 65cc50b..21fb989 100644 (file)
@@ -133,7 +133,7 @@ class Selector(BaseProxy):
         return func(*args, **kwargs)
     
     def get_supportsReplace(self):
-        self._pgetter(self._dbus_interface, "supportsReplace")
+        return self._pgetter(self._dbus_interface, "supportsReplace")
     def set_supportsReplace(self, value):
         self._psetter(self._dbus_interface, "supportsReplace", value)
     _supportsReplaceDoc = \
index 6ee3419..e69f9f4 100644 (file)
@@ -62,17 +62,6 @@ class ContentStream(BaseProxy):
         func = self.get_dbus_method("seek")
         return func(*args, **kwargs)
     
-    def unimplemented(self, *args, **kwargs):
-        """
-        /cond
-        """
-        func = self.get_dbus_method("unimplemented")
-        return func(*args, **kwargs)
-    
-    def unimplemented2(self, *args, **kwargs):
-        func = self.get_dbus_method("unimplemented2")
-        return func(*args, **kwargs)
-    
     class IOError(Exception):
         pass
     
index fdce8a7..26cee38 100644 (file)
@@ -305,7 +305,7 @@ class Table(BaseProxy):
         return func(*args, **kwargs)
     
     def get_caption(self):
-        self._pgetter(self._dbus_interface, "caption")
+        return self._pgetter(self._dbus_interface, "caption")
     def set_caption(self, value):
         self._psetter(self._dbus_interface, "caption", value)
     _captionDoc = \
@@ -315,7 +315,7 @@ class Table(BaseProxy):
     caption = property(fget=get_caption, fset=set_caption, doc=_captionDoc)
     
     def get_nColumns(self):
-        self._pgetter(self._dbus_interface, "nColumns")
+        return self._pgetter(self._dbus_interface, "nColumns")
     def set_nColumns(self, value):
         self._psetter(self._dbus_interface, "nColumns", value)
     _nColumnsDoc = \
@@ -328,7 +328,7 @@ class Table(BaseProxy):
     nColumns = property(fget=get_nColumns, fset=set_nColumns, doc=_nColumnsDoc)
     
     def get_nRows(self):
-        self._pgetter(self._dbus_interface, "nRows")
+        return self._pgetter(self._dbus_interface, "nRows")
     def set_nRows(self, value):
         self._psetter(self._dbus_interface, "nRows", value)
     _nRowsDoc = \
@@ -340,7 +340,7 @@ class Table(BaseProxy):
     nRows = property(fget=get_nRows, fset=set_nRows, doc=_nRowsDoc)
     
     def get_nSelectedColumns(self):
-        self._pgetter(self._dbus_interface, "nSelectedColumns")
+        return self._pgetter(self._dbus_interface, "nSelectedColumns")
     def set_nSelectedColumns(self, value):
         self._psetter(self._dbus_interface, "nSelectedColumns", value)
     _nSelectedColumnsDoc = \
@@ -351,7 +351,7 @@ class Table(BaseProxy):
     nSelectedColumns = property(fget=get_nSelectedColumns, fset=set_nSelectedColumns, doc=_nSelectedColumnsDoc)
     
     def get_nSelectedRows(self):
-        self._pgetter(self._dbus_interface, "nSelectedRows")
+        return self._pgetter(self._dbus_interface, "nSelectedRows")
     def set_nSelectedRows(self, value):
         self._psetter(self._dbus_interface, "nSelectedRows", value)
     _nSelectedRowsDoc = \
@@ -362,7 +362,7 @@ class Table(BaseProxy):
     nSelectedRows = property(fget=get_nSelectedRows, fset=set_nSelectedRows, doc=_nSelectedRowsDoc)
     
     def get_summary(self):
-        self._pgetter(self._dbus_interface, "summary")
+        return self._pgetter(self._dbus_interface, "summary")
     def set_summary(self, value):
         self._psetter(self._dbus_interface, "summary", value)
     _summaryDoc = \
index 3363585..f82f0c3 100644 (file)
@@ -28,10 +28,10 @@ class TestApplicationCache(object):
        Test application cache. Accesses single AccessibleCache.
        """
 
-       def __init__(self, connection, bus_name):
+       def __init__(self, registry, connection, bus_name):
                self._connection = connection
                self._bus_name = bus_name
-               self._accessible_cache = AccessibleCache(connection, bus_name)
+               self._accessible_cache = AccessibleCache(registry, connection, bus_name)
 
        def __getitem__(self, key):
                return self._accessible_cache
@@ -42,12 +42,13 @@ class TestApplicationCache(object):
                else:
                        return False
 
-       def get_application_at_index(self, index):
+       def get_application_at_index(self, index, parent):
                return create_accessible(self,
                                         self._bus_name, 
                                         self._accessible_cache.root, 
                                         interfaces.ATSPI_ACCESSIBLE,
-                                        connection=self._connection)
+                                        connection=self._connection,
+                                        parent=parent)
 
        def get_application_count(self):
                return 1
index 28aca21..41ddcd1 100644 (file)
@@ -12,6 +12,8 @@
 #along with this program; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
+import dbus
+
 import interfaces
 from base import BaseProxy, Enum
 from factory import add_accessible_class
@@ -191,14 +193,14 @@ class Text(BaseProxy):
         func = self.get_dbus_method("getAttributeValue")
         return func(*args, **kwargs)
     
-    def getAttributes(self, *args, **kwargs):
+    def getAttributes(self, offset):
         """
         getAttributes is deprecated in favor of getAttributeRun. 
         @return the attributes at offset, as a semicolon-delimited set
         of colon-delimited name-value pairs.
         """
         func = self.get_dbus_method("getAttributes")
-        return func(*args, **kwargs)
+        return func(dbus.Int32(offset))
     
     def getBoundedRanges(self, *args, **kwargs):
         """
@@ -370,7 +372,7 @@ class Text(BaseProxy):
         func = self.get_dbus_method("getSelection")
         return func(*args, **kwargs)
     
-    def getText(self, *args, **kwargs):
+    def getText(self, startOffset, endOffset):
         """
         Obtain all or part of the onscreen textual content of a Text
         object. If endOffset is specified as "-1", then this method will
@@ -380,7 +382,9 @@ class Text(BaseProxy):
         at endOffset.
         """
         func = self.get_dbus_method("getText")
-        return func(*args, **kwargs)
+       if not endOffset:
+               endOffset = -1
+        return func(dbus.Int32(startOffset), dbus.Int32(endOffset))
     
     def getTextAfterOffset(self, *args, **kwargs):
         """
@@ -509,7 +513,7 @@ class Text(BaseProxy):
         return func(*args, **kwargs)
 
     def get_caretOffset(self):
-        self._pgetter(self._dbus_interface, "caretOffset")
+        return self._pgetter(self._dbus_interface, "caretOffset")
     def set_caretOffset(self, value):
         self._psetter(self._dbus_interface, "caretOffset", value)
     _caretOffsetDoc = \
@@ -524,7 +528,7 @@ class Text(BaseProxy):
     caretOffset = property(fget=get_caretOffset, fset=set_caretOffset, doc=_caretOffsetDoc)
     
     def get_characterCount(self):
-        self._pgetter(self._dbus_interface, "characterCount")
+        return self._pgetter(self._dbus_interface, "characterCount")
     def set_characterCount(self, value):
         self._psetter(self._dbus_interface, "characterCount", value)
     _characterCountDoc = \
index f086bdc..8d3b7cc 100644 (file)
 
 #authors: Peter Parente, Mark Doffman
 
+import relation
+import state
+import registry
+
+__all__ = [
+               "setCacheLevel",
+               "getCacheLevel",
+               "clearCache",
+               "printCache",
+               "getInterfaceIID",
+               "getInterfaceName",
+               "listInterfaces",
+               "stringToConst",
+               "stateToString",
+               "stateToString",
+               "allModifiers",
+               "findDescendant",
+               "findAllDescendants",
+               "findAncestor",
+               "getPath",
+        ]
+
 def setCacheLevel(level):
        pass
 
@@ -61,10 +83,6 @@ def getInterfaceName(obj):
        """
        return obj._dbus_interface.lstrip("org.freedesktop.atspi.")
 
-# we're importing here to avoid cyclic importants; constants relies on the
-# two functions above
-import constants
-
 def listInterfaces(obj):
        """
        Gets a list of the names of all interfaces supported by this object. The
@@ -121,7 +139,7 @@ def stateToString(value):
        @return: Human readable, untranslated name of the state
        @rtype: string
        """
-       return constants.STATE_VALUE_TO_NAME.get(value)
+       return state.STATE_VALUE_TO_NAME.get(value)
 
 def relationToString(value):
        """
@@ -133,7 +151,7 @@ def relationToString(value):
        @return: Human readable, untranslated name of the relation
        @rtype: string
        """
-       return constants.RELATION_VALUE_TO_NAME.get(value)
+       return relation.RELATION_VALUE_TO_NAME.get(value)
 
 def allModifiers():
        """
@@ -141,7 +159,7 @@ def allModifiers():
        L{registry.Registry.registerKeystrokeListener}.
        """
        mask = 0
-       while mask <= (1 << constants.MODIFIER_NUMLOCK):
+       while mask <= (1 << registry.MODIFIER_NUMLOCK):
                yield mask
                mask += 1
 
@@ -311,5 +329,3 @@ def getPath(acc):
                except Exception:
                        raise LookupError
                acc = acc.parent
-
-del constants
index ec54854..6f931df 100644 (file)
@@ -31,7 +31,7 @@ class Value(BaseProxy):
     """
 
     def get_currentValue(self):
-        self._pgetter(self._dbus_interface, "currentValue")
+        return self._pgetter(self._dbus_interface, "currentValue")
     def set_currentValue(self, value):
         self._psetter(self._dbus_interface, "currentValue", value)
     _currentValueDoc = \
@@ -41,7 +41,7 @@ class Value(BaseProxy):
     currentValue = property(fget=get_currentValue, fset=set_currentValue, doc=_currentValueDoc)
     
     def get_maximumValue(self):
-        self._pgetter(self._dbus_interface, "maximumValue")
+        return self._pgetter(self._dbus_interface, "maximumValue")
     def set_maximumValue(self, value):
         self._psetter(self._dbus_interface, "maximumValue", value)
     _maximumValueDoc = \
@@ -51,7 +51,7 @@ class Value(BaseProxy):
     maximumValue = property(fget=get_maximumValue, fset=set_maximumValue, doc=_maximumValueDoc)
     
     def get_minimumIncrement(self):
-        self._pgetter(self._dbus_interface, "minimumIncrement")
+        return self._pgetter(self._dbus_interface, "minimumIncrement")
     def set_minimumIncrement(self, value):
         self._psetter(self._dbus_interface, "minimumIncrement", value)
     _minimumIncrementDoc = \
@@ -63,7 +63,7 @@ class Value(BaseProxy):
     minimumIncrement = property(fget=get_minimumIncrement, fset=set_minimumIncrement, doc=_minimumIncrementDoc)
     
     def get_minimumValue(self):
-        self._pgetter(self._dbus_interface, "minimumValue")
+        return self._pgetter(self._dbus_interface, "minimumValue")
     def set_minimumValue(self, value):
         self._psetter(self._dbus_interface, "minimumValue", value)
     _minimumValueDoc = \