2009-03-12 Mark Doffman <mark.doffman@codethink.co.uk>
authorMark Doffman <mdoff@silver-wind.(none)>
Thu, 12 Mar 2009 16:36:38 +0000 (16:36 +0000)
committerMark Doffman <mdoff@silver-wind.(none)>
Thu, 12 Mar 2009 16:36:38 +0000 (16:36 +0000)
        * 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
pyatspi/accessible.py
pyatspi/accessiblecache.py
pyatspi/applicationcache.py
pyatspi/base.py
pyatspi/desktop.py
pyatspi/registry.py

index 494763b..d235c2e 100644 (file)
@@ -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 (&registration_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 (&registration_mutex);
+}
+
+static void
+spi_atk_register_toplevel_removed (AtkObject *accessible,
+                                   guint     index,
+                                   AtkObject *child)
+{
+  g_static_rec_mutex_lock (&registration_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 (&registration_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------------------------------------------------------------------------*/
-
index e86b73b..549f022 100644 (file)
@@ -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):
index 3a87c15..37dbe96 100644 (file)
@@ -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,
index cbf4b9d..96a9830 100644 (file)
@@ -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:
index 7adafbb..1a7141a 100644 (file)
@@ -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)
 
index 4101ae0..eb26ae0 100644 (file)
@@ -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.
index 3f7088f..8dc2036 100644 (file)
@@ -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):