OSDN Git Service

AppModule now has a terminate() method instead of using __del__() to clean up.
authorJames Teh <jamie@jantrid.net>
Tue, 7 Dec 2010 06:28:40 +0000 (16:28 +1000)
committerJames Teh <jamie@jantrid.net>
Tue, 7 Dec 2010 06:28:40 +0000 (16:28 +1000)
This is necessary because it is possible that some app modules might not be garbage collected until after NVDAHelper is terminated and app module termination depends on NVDAHelper still being initialised. All running app modules are explicitly terminated on exit before NVDAHelper terminates.
Fixes many unlogged exceptions (resulting in a strange sound) when NVDA exits.
Also, fix typo in appModuleHandler.update() which might have caused getAppModuleFromProcessID() to be called more than it should, although this wouldn't have been noticeable in reality.

Fixes #1263.

source/appModuleHandler.py
source/core.py

index b795e05..6fb9ea6 100644 (file)
@@ -94,17 +94,22 @@ def getAppModuleFromProcessID(processID):
        return mod\r
 \r
 def update(processID):\r
-       """Removes any appModules from te cache who's process has died, and also tries to load a new appModule for the given process ID if need be.\r
+       """Removes any appModules from the cache whose process has died, and also tries to load a new appModule for the given process ID if need be.\r
        @param processID: the ID of the process.\r
        @type processID: int\r
        """\r
        for deadMod in [mod for mod in runningTable.itervalues() if not mod.isAlive]:\r
                log.debug("application %s closed"%deadMod.appName)\r
-               del runningTable[deadMod.processID];\r
+               del runningTable[deadMod.processID]\r
                if deadMod in set(o.appModule for o in api.getFocusAncestors()+[api.getFocusObject()] if o and o.appModule):\r
                        if hasattr(deadMod,'event_appLoseFocus'):\r
-                               deadMod.event_appLoseFocus();\r
-               getAppModuleFromProcessID(processID)\r
+                               deadMod.event_appLoseFocus()\r
+               try:\r
+                       deadMod.terminate()\r
+               except:\r
+                       log.exception("Error terminating app module %r" % deadMod)\r
+       # This creates a new app module if necessary.\r
+       getAppModuleFromProcessID(processID)\r
 \r
 def doesAppModuleExist(name):\r
        return any(importer.find_module("appModules.%s" % name) for importer in _importers)\r
@@ -147,6 +152,14 @@ def initialize():
        config.addConfigDirsToPythonPackagePath(appModules)\r
        _importers=list(pkgutil.iter_importers("appModules.__init__"))\r
 \r
+def terminate():\r
+       for processID, app in runningTable.iteritems():\r
+               try:\r
+                       app.terminate()\r
+               except:\r
+                       log.exception("Error terminating app module %r" % app)\r
+       runningTable.clear()\r
+\r
 #base class for appModules\r
 class AppModule(baseObject.ScriptableObject):\r
        """Base app module.\r
@@ -191,7 +204,11 @@ class AppModule(baseObject.ScriptableObject):
        def _get_isAlive(self):\r
                return bool(winKernel.waitForSingleObject(self.processHandle,0))\r
 \r
-       def __del__(self):\r
+       def terminate(self):\r
+               """Terminate this app module.\r
+               This is called to perform any clean up when this app module is being destroyed.\r
+               Subclasses should call the superclass method first.\r
+               """\r
                winKernel.closeHandle(self.processHandle)\r
                NVDAHelper.localLib.destroyConnection(self.helperLocalBindingHandle)\r
 \r
index 623f528..4ea205e 100644 (file)
@@ -306,6 +306,8 @@ This initializes all modules such as audio, IAccessible, keyboard, mouse, and GU
                JABHandler.terminate()\r
        except:\r
                log.error("Error terminating Java Access Bridge support",exc_info=True)\r
+       log.debug("Terminating app module handler")\r
+       appModuleHandler.terminate()\r
        log.debug("Terminating NVDAHelper")\r
        try:\r
                NVDAHelper.terminate()\r