From c767935ed5f324a9b498b78bd19c1b354aa06575 Mon Sep 17 00:00:00 2001 From: Mark Doffman Date: Thu, 12 Mar 2009 16:36:38 +0000 Subject: [PATCH] 2009-03-12 Mark Doffman * atk-adaptor/accessible-register.c Add 'object:children-changed' signal emission on addition or removal of top-level objects. * pyatspi/* Changes neccessary to have accercier pick up new top level windows. Add correct hash function to accessible objects. --- atk-adaptor/accessible-register.c | 68 ++++++++++++++++++++++++++++++++++++++- pyatspi/accessible.py | 4 ++- pyatspi/accessiblecache.py | 2 +- pyatspi/applicationcache.py | 22 +++++++------ pyatspi/base.py | 3 ++ pyatspi/desktop.py | 10 +++++- pyatspi/registry.py | 13 +++++--- 7 files changed, 105 insertions(+), 17 deletions(-) diff --git a/atk-adaptor/accessible-register.c b/atk-adaptor/accessible-register.c index 494763b..d235c2e 100644 --- a/atk-adaptor/accessible-register.c +++ b/atk-adaptor/accessible-register.c @@ -489,6 +489,7 @@ tree_update_children_listener (GSignalInvocationHint *signal_hint, #endif } register_subtree (child); + update_accessible (accessible); } recursion_check_unset (); @@ -499,6 +500,63 @@ tree_update_children_listener (GSignalInvocationHint *signal_hint, return TRUE; } +static void +spi_atk_register_toplevel_added (AtkObject *accessible, + guint index, + AtkObject *child) +{ + g_static_rec_mutex_lock (®istration_mutex); + + g_return_if_fail (ATK_IS_OBJECT (accessible)); + + if (object_to_ref (accessible)) + { +#ifdef SPI_ATK_DEBUG + if (recursion_check_and_set ()) + g_warning ("AT-SPI: Recursive use of registration module"); + + g_debug ("AT-SPI: Toplevel added listener"); +#endif + if (!ATK_IS_OBJECT (child)) + { + child = atk_object_ref_accessible_child (accessible, index); +#ifdef SPI_ATK_DEBUG + non_owned_accessible (child); +#endif + } + register_subtree (child); + update_accessible (accessible); + + recursion_check_unset (); + } + + g_static_rec_mutex_unlock (®istration_mutex); +} + +static void +spi_atk_register_toplevel_removed (AtkObject *accessible, + guint index, + AtkObject *child) +{ + g_static_rec_mutex_lock (®istration_mutex); + + g_return_if_fail (ATK_IS_OBJECT (accessible)); + + if (object_to_ref (accessible)) + { +#ifdef SPI_ATK_DEBUG + if (recursion_check_and_set ()) + g_warning ("AT-SPI: Recursive use of registration module"); + + g_debug ("AT-SPI: Toplevel removed listener"); +#endif + update_accessible (accessible); + recursion_check_unset (); + } + + g_static_rec_mutex_unlock (®istration_mutex); +} + /* * Initializes required global data. The update and removal lists * and the reference lookup tables. @@ -522,7 +580,15 @@ atk_dbus_initialize (AtkObject *root) atk_add_global_event_listener (tree_update_listener, "Gtk:AtkObject:property-change"); atk_add_global_event_listener (tree_update_children_listener, "Gtk:AtkObject:children-changed"); + + g_signal_connect (root, + "children-changed::add", + (GCallback) spi_atk_register_toplevel_added, + NULL); + g_signal_connect (root, + "children-changed::remove", + (GCallback) spi_atk_register_toplevel_removed, + NULL); } /*END------------------------------------------------------------------------*/ - diff --git a/pyatspi/accessible.py b/pyatspi/accessible.py index e86b73b..549f022 100644 --- a/pyatspi/accessible.py +++ b/pyatspi/accessible.py @@ -154,10 +154,12 @@ class Accessible(BaseProxy): def getIndexInParent(self): """ - Get the index of this object in its parent's child list. + Get the index of this object in its parent's child list. @return : a long integer indicating this object's index in the parent's list. """ + if self.parent == None: + return -1 for i in range(0, self.parent.childCount): child = self.parent.getChildAtIndex(i) if self.isEqual(child): diff --git a/pyatspi/accessiblecache.py b/pyatspi/accessiblecache.py index 3a87c15..37dbe96 100644 --- a/pyatspi/accessiblecache.py +++ b/pyatspi/accessiblecache.py @@ -139,7 +139,7 @@ class AccessibleCache(object): ("parent", 0, 0, "")) self._registry._notifyParentChange(event) - added, removed = _list_items_added_removed (olddata.children, newdata.children) + removed, added = _list_items_added_removed (olddata.children, newdata.children) if added: event = _Event(self._registry.cache, diff --git a/pyatspi/applicationcache.py b/pyatspi/applicationcache.py index cbf4b9d..96a9830 100644 --- a/pyatspi/applicationcache.py +++ b/pyatspi/applicationcache.py @@ -15,7 +15,7 @@ import dbus from accessiblecache import AccessibleCache -from desktop import Desktop +from desktop import Desktop, DESKTOP_PATH from factory import accessible_factory from event import Event as _Event from base import AccessibleObjectNotAvailable @@ -29,8 +29,11 @@ __all__ = [ #------------------------------------------------------------------------------ +ROOT_PATH = '/org/freedesktop/atspi/accessible/root' + +#------------------------------------------------------------------------------ + class TestApplicationCache(object): - _DESKTOP_PATH = '/org/freedesktop/atspi/accessible/desktop' """ Test application store, accesses a single application. @@ -88,8 +91,10 @@ class TestApplicationCache(object): provided here so that another one is not created. """ # An acc_path of '/' implies the desktop object, whatever the app_name. - if acc_path == TestApplicationCache._DESKTOP_PATH: + if acc_path == DESKTOP_PATH: return Desktop(self) + if acc_path == ROOT_PATH: + return None else: cls = accessible_factory.get_accessible_class(interface) try: @@ -123,9 +128,6 @@ class ApplicationCache(object): D-Bus path. """ - # An accessible path of '/' implies the desktop object, whatever the application name. - _DESKTOP_PATH = '/org/freedesktop/atspi/accessible/root' - _APPLICATIONS_ADD = 1 _APPLICATIONS_REMOVE = 0 @@ -159,7 +161,7 @@ class ApplicationCache(object): self._connection, bus_name) event = _Event(self, - ApplicationCache._DESKTOP_PATH, + DESKTOP_PATH, ATSPI_REGISTRY_NAME, "org.freedesktop.atspi.Event.Object", "children-changed", @@ -169,7 +171,7 @@ class ApplicationCache(object): self.application_list.remove(bus_name) del(self.application_cache[bus_name]) event = _Event(self, - ApplicationCache._DESKTOP_PATH, + DESKTOP_PATH, ATSPI_REGISTRY_NAME, "org.freedesktop.atspi.Event.Object", "children-changed", @@ -213,8 +215,10 @@ class ApplicationCache(object): @dbus_object: If a D-Bus object already exists for the accessible object it can be provided here so that another one is not created. """ - if acc_path == ApplicationCache._DESKTOP_PATH: + if acc_path == DESKTOP_PATH: return Desktop(self) + if acc_path == ROOT_PATH: + return None else: cls = accessible_factory.get_accessible_class(interface) try: diff --git a/pyatspi/base.py b/pyatspi/base.py index 7adafbb..1a7141a 100644 --- a/pyatspi/base.py +++ b/pyatspi/base.py @@ -131,6 +131,9 @@ class BaseProxy(object): def __ne__(self, other): return not self.__eq__(other) + def __hash__(self): + return hash(self._app_name + self._acc_path) + def get_dbus_method(self, *args, **kwargs): method = self._dbus_object.get_dbus_method(*args, **kwargs) diff --git a/pyatspi/desktop.py b/pyatspi/desktop.py index 4101ae0..eb26ae0 100644 --- a/pyatspi/desktop.py +++ b/pyatspi/desktop.py @@ -22,10 +22,15 @@ from component import LAYER_WIDGET __all__ = [ "Desktop", + "DESKTOP_PATH", ] #------------------------------------------------------------------------------ +DESKTOP_PATH = '/org/freedesktop/atspi/accessible/desktop' + +#------------------------------------------------------------------------------ + class DesktopComponent(object): """ The Component interface is implemented by objects which occupy @@ -164,7 +169,7 @@ class Desktop(object): """ self._appcache = cache self._app_name = ':' - self._acc_path = '/' + self._acc_path = DESKTOP_PATH def __str__(self): try: @@ -197,6 +202,9 @@ class Desktop(object): def __ne__(self, other): return not self.__eq__(other) + def __hash__(self): + return hash(self._app_name + self._acc_path) + def getApplication(self): """ Get the containing Application for this object. diff --git a/pyatspi/registry.py b/pyatspi/registry.py index 3f7088f..8dc2036 100644 --- a/pyatspi/registry.py +++ b/pyatspi/registry.py @@ -196,6 +196,9 @@ class _Registry(object): if new_type.is_subtype(type): registered.append(new_type.name) + if registered == []: + del(register[client]) + def _deregisterFake(self, type, register, client, *names): """ Deregisters a client from a register of clients @@ -209,8 +212,9 @@ class _Registry(object): for name in names: remove_type = _EventType(name) - for i in range(0, len(registered) - 1): - type_name = registered[i] + copy = registered[:] + for i in range(0, len(copy)): + type_name = copy[i] registered_type = _EventType(type_name) if remove_type.is_subtype(registered_type): @@ -285,8 +289,9 @@ class _Registry(object): for name in names: remove_type = _EventType(name) - for i in range (0, len(registered)): - type_name, signal_match = registered[i] + copy = registered[:] + for i in range (0, len(copy)): + type_name, signal_match = copy[i] registered_type = _EventType(type_name) if remove_type.is_subtype(registered_type): -- 2.7.4