2009-27-09 Mark Doffman <mark.doffman@codethink.co.uk>
[platform/core/uifw/at-spi2-atk.git] / pyatspi / applicationcache.py
index a50c51b..68fa65a 100644 (file)
 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
 
 from interfaces import *
 
@@ -28,7 +29,12 @@ __all__ = [
 
 #------------------------------------------------------------------------------
 
+ROOT_PATH    = '/org/freedesktop/atspi/accessible/root'
+
+#------------------------------------------------------------------------------
+
 class TestApplicationCache(object):
+
         """
         Test application store, accesses a single application.
 
@@ -64,7 +70,10 @@ class TestApplicationCache(object):
                 available at the given D-Bus name.
                 """
                 cls = accessible_factory.get_accessible_class(ATSPI_APPLICATION)
-                return cls(app_name, self.application_cache[app_name].root, self, ATSPI_APPLICATION)
+                try:
+                        return cls(app_name, self.application_cache[app_name].root, self, ATSPI_APPLICATION)
+                except KeyError:
+                        raise AccessibleObjectNotAvailable ()
 
         def create_accessible(self, app_name, acc_path, interface, dbus_object=None):
                 """
@@ -82,11 +91,16 @@ 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 == '/':
+                if acc_path == DESKTOP_PATH:
                         return Desktop(self)
+                if acc_path == ROOT_PATH:
+                        return None
                 else:
                         cls = accessible_factory.get_accessible_class(interface)
-                        return cls(app_name, acc_path, self, interface, dbus_object=dbus_object)
+                        try:
+                                return cls(app_name, acc_path, self, interface, dbus_object=dbus_object)
+                        except KeyError:
+                                raise AccessibleObjectNotAvailable ()
 
         @property
         def connection(self):
@@ -114,9 +128,6 @@ class ApplicationCache(object):
                      D-Bus path.
         """
 
-        # An accessible path of '/' implies the desktop object, whatever the application name.
-        _DESKTOP_PATH = '/'
-
         _APPLICATIONS_ADD = 1
         _APPLICATIONS_REMOVE = 0
 
@@ -143,20 +154,24 @@ class ApplicationCache(object):
         def update_handler (self, update_type, bus_name):
                 if update_type == ApplicationCache._APPLICATIONS_ADD:
                         #TODO Check that app does not already exist
-                        self.application_list.append(bus_name)
-                        self.application_cache[bus_name] = AccessibleCache(self._registry, self._connection, bus_name)
-                        event = _Event(self,
-                                       ApplicationCache._DESKTOP_PATH,
-                                       ATSPI_REGISTRY_NAME,
-                                       "org.freedesktop.atspi.Event.Object",
-                                       "children-changed",
-                                       ("add", 0, 0, ""))
+                        #TODO Excuding this app is a hack, need to have re-entrant method calls.
+                        if bus_name != self._connection.get_unique_name ():
+                                self.application_list.append(bus_name)
+                                self.application_cache[bus_name] = AccessibleCache(self._registry,
+                                                                                   self._connection,
+                                                                                   bus_name)
+                                event = _Event(self,
+                                               DESKTOP_PATH,
+                                               ATSPI_REGISTRY_NAME,
+                                               "org.freedesktop.atspi.Event.Object",
+                                               "children-changed",
+                                               ("add", 0, 0, ""))
                 elif update_type == ApplicationCache._APPLICATIONS_REMOVE:
                         #TODO Fail safely if app does not exist
                         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",
@@ -180,7 +195,10 @@ class ApplicationCache(object):
                         return Desktop(self)
                 else:
                         cls = accessible_factory.get_accessible_class(ATSPI_APPLICATION)
-                        return cls(app_name, self.application_cache[app_name].root, self, ATSPI_APPLICATION)
+                        try:
+                                return cls(app_name, self.application_cache[app_name].root, self, ATSPI_APPLICATION)
+                        except KeyError:
+                                raise AccessibleObjectNotAvailable ()
 
         def create_accessible(self, app_name, acc_path, interface, dbus_object=None):
                 """
@@ -197,11 +215,16 @@ 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)
-                        return cls(app_name, acc_path, self, interface, dbus_object=dbus_object)
+                        try:
+                                return cls(app_name, acc_path, self, interface, dbus_object=dbus_object)
+                        except KeyError:
+                                raise AccessibleObjectNotAvailable ()
 
         @property
         def connection(self):
@@ -210,4 +233,16 @@ class ApplicationCache(object):
                 """
                 return self._connection
 
+        def _refresh(self):
+                new = self._app_register.getApplications()
+                removed = [item for item in self.application_list if item not in new]
+                added   = [item for item in new if item not in self.application_list]
+                for item in added:
+                        self.update_handler (self._APPLICATIONS_ADD, item)
+                for item in removed:
+                        self.update_handler (self._APPLICATIONS_REMOVE, item)
+
+                for item in self.application_cache.values():
+                        item._refresh()
+
 #END----------------------------------------------------------------------------