Skip to content

Commit

Permalink
The reload plugins command no longer causes problems for triggered co…
Browse files Browse the repository at this point in the history
…nfiguration profiles, new documents in web browsers and screen review. (#6390)

When reloading app modules, transfer necessary state (the nvdaHelperRemote connection and config profile trigger) from the old AppModule instances to the newly loaded instances. Ensure the focus object, focus ancestors and navigator object know about their new AppModule.
  • Loading branch information
jcsteh committed Oct 11, 2016
1 parent 086386a commit dcb6fd0
Showing 1 changed file with 30 additions and 1 deletion.
31 changes: 30 additions & 1 deletion source/appModuleHandler.py
Expand Up @@ -178,16 +178,43 @@ def fetchAppModule(processID,appName):
def reloadAppModules():
"""Reloads running appModules.
especially, it clears the cache of running appModules and deletes them from sys.modules.
Each appModule will be reloaded immediately as a reaction on a first event coming from the process.
Each appModule will then be reloaded immediately.
"""
global appModules
state = []
for mod in runningTable.itervalues():
state.append({key: getattr(mod, key) for key in ("processID",
# #2892: We must save nvdaHelperRemote handles, as we can't reinitialize without a foreground/focus event.
# Also, if there is an active context handle such as a loaded buffer,
# nvdaHelperRemote can't reinit until that handle dies.
"helperLocalBindingHandle", "_inprocRegistrationHandle",
# #5380: We must save config profile triggers so they can be cleaned up correctly.
# Otherwise, they'll remain active forever.
"_configProfileTrigger",
) if hasattr(mod, key)})
# #2892: Don't disconnect from nvdaHelperRemote during termination.
mod._helperPreventDisconnect = True
terminate()
del appModules
mods=[k for k,v in sys.modules.iteritems() if k.startswith("appModules") and v is not None]
for mod in mods:
del sys.modules[mod]
import appModules
initialize()
for entry in state:
pid = entry.pop("processID")
mod = getAppModuleFromProcessID(pid)
mod.__dict__.update(entry)
# The appModule property for existing NVDAObjects will now be None, since their AppModule died.
# Force focus, navigator, etc. objects to re-fetch,
# since NVDA depends on the appModule property for these.
for obj in itertools.chain((api.getFocusObject(), api.getNavigatorObject()), api.getFocusAncestors()):
try:
del obj._appModuleRef
except AttributeError:
continue
# Fetch and cache right away; the process could die any time.
obj.appModule

def initialize():
"""Initializes the appModule subsystem.
Expand Down Expand Up @@ -381,6 +408,8 @@ def terminate(self):
Subclasses should call the superclass method first.
"""
winKernel.closeHandle(self.processHandle)
if getattr(self, "_helperPreventDisconnect", False):
return
if self._inprocRegistrationHandle:
ctypes.windll.rpcrt4.RpcSsDestroyClientContext(ctypes.byref(self._inprocRegistrationHandle))
if self.helperLocalBindingHandle:
Expand Down

0 comments on commit dcb6fd0

Please sign in to comment.