From: Mark Doffman Date: Mon, 8 Sep 2008 08:40:42 +0000 (+0100) Subject: 2008-09-08 Mark Doffman X-Git-Tag: AT_SPI2_ATK_2_12_0~594 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fat-spi2-atk.git;a=commitdiff_plain;h=b93edf847d229f40394cb0b4f721c4c2a5897d84 2008-09-08 Mark Doffman * 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 --- diff --git a/atk-adaptor/text.c b/atk-adaptor/text.c index c22b0ea..451a92b 100644 --- a/atk-adaptor/text.c +++ b/atk-adaptor/text.c @@ -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; } diff --git a/atk-adaptor/tree.c b/atk-adaptor/tree.c index 7efca21..00ec003 100644 --- a/atk-adaptor/tree.c +++ b/atk-adaptor/tree.c @@ -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 index 0000000..526b71f --- /dev/null +++ b/pyatspi/Accessibility.py @@ -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 * diff --git a/pyatspi/__init__.py b/pyatspi/__init__.py index 12be5df..510e65b 100644 --- a/pyatspi/__init__.py +++ b/pyatspi/__init__.py @@ -12,38 +12,12 @@ #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 * diff --git a/pyatspi/accessible.py b/pyatspi/accessible.py index 86802c5..39584ca 100644 --- a/pyatspi/accessible.py +++ b/pyatspi/accessible.py @@ -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 diff --git a/pyatspi/application.py b/pyatspi/application.py index c0c8284..12abe5a 100644 --- a/pyatspi/application.py +++ b/pyatspi/application.py @@ -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 = \ diff --git a/pyatspi/base.py b/pyatspi/base.py index 4fabeec..c950ec8 100644 --- a/pyatspi/base.py +++ b/pyatspi/base.py @@ -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---------------------------------------------------------------------------- diff --git a/pyatspi/cache.py b/pyatspi/cache.py index 56ab0f6..e744ca5 100644 --- a/pyatspi/cache.py +++ b/pyatspi/cache.py @@ -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--------------------------------------------------------------------------- diff --git a/pyatspi/constants.py b/pyatspi/constants.py index db3b971..006723c 100644 --- a/pyatspi/constants.py +++ b/pyatspi/constants.py @@ -138,3 +138,5 @@ EVENT_TREE = { 'focus' : ['focus:'] } + +from Accessibility import * diff --git a/pyatspi/desktop.py b/pyatspi/desktop.py index 37898c2..1cbf1e8 100644 --- a/pyatspi/desktop.py +++ b/pyatspi/desktop.py @@ -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 diff --git a/pyatspi/event.py b/pyatspi/event.py index c7ef618..4ae61ee 100644 --- a/pyatspi/event.py +++ b/pyatspi/event.py @@ -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 diff --git a/pyatspi/hyperlink.py b/pyatspi/hyperlink.py index 96f7141..01afd4e 100644 --- a/pyatspi/hyperlink.py +++ b/pyatspi/hyperlink.py @@ -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 = \ diff --git a/pyatspi/image.py b/pyatspi/image.py index 0190bb3..bf9beb5 100644 --- a/pyatspi/image.py +++ b/pyatspi/image.py @@ -12,9 +12,11 @@ #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 = \ diff --git a/pyatspi/registry.py b/pyatspi/registry.py index 164fa49..96c3d10 100644 --- a/pyatspi/registry.py +++ b/pyatspi/registry.py @@ -19,17 +19,86 @@ #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 diff --git a/pyatspi/selection.py b/pyatspi/selection.py index 8e690b5..3811061 100644 --- a/pyatspi/selection.py +++ b/pyatspi/selection.py @@ -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 = \ diff --git a/pyatspi/selector.py b/pyatspi/selector.py index 65cc50b..21fb989 100644 --- a/pyatspi/selector.py +++ b/pyatspi/selector.py @@ -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 = \ diff --git a/pyatspi/streamablecontent.py b/pyatspi/streamablecontent.py index 6ee3419..e69f9f4 100644 --- a/pyatspi/streamablecontent.py +++ b/pyatspi/streamablecontent.py @@ -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 diff --git a/pyatspi/table.py b/pyatspi/table.py index fdce8a7..26cee38 100644 --- a/pyatspi/table.py +++ b/pyatspi/table.py @@ -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 = \ diff --git a/pyatspi/test.py b/pyatspi/test.py index 3363585..f82f0c3 100644 --- a/pyatspi/test.py +++ b/pyatspi/test.py @@ -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 diff --git a/pyatspi/text.py b/pyatspi/text.py index 28aca21..41ddcd1 100644 --- a/pyatspi/text.py +++ b/pyatspi/text.py @@ -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 = \ diff --git a/pyatspi/utils.py b/pyatspi/utils.py index f086bdc..8d3b7cc 100644 --- a/pyatspi/utils.py +++ b/pyatspi/utils.py @@ -19,6 +19,28 @@ #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 diff --git a/pyatspi/value.py b/pyatspi/value.py index ec54854..6f931df 100644 --- a/pyatspi/value.py +++ b/pyatspi/value.py @@ -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 = \