diff --git a/source/gui/__init__.py b/source/gui/__init__.py index 7a4e46e7851..368e537acd5 100644 --- a/source/gui/__init__.py +++ b/source/gui/__init__.py @@ -597,6 +597,21 @@ def initialize(): raise RuntimeError("GUI already initialized") mainFrame = MainFrame() wx.GetApp().SetTopWindow(mainFrame) + # In wxPython >= 4.1, + # wx.CallAfter no longer executes callbacks while NVDA's main thread is within apopup menu or message box. + # To work around this, + # Monkeypatch wx.CallAfter to + # post a WM_NULL message to our top-level window after calling the original CallAfter, + # which causes wx's event loop to wake up enough to execute the callback. + old_wx_CallAfter = wx.CallAfter + + def wx_CallAfter_wrapper(func, *args, **kwargs): + old_wx_CallAfter(func, *args, **kwargs) + # mainFrame may be None as NVDA could be terminating. + topHandle = mainFrame.Handle if mainFrame else None + if topHandle: + winUser.PostMessage(topHandle, winUser.WM_NULL, 0, 0) + wx.CallAfter = wx_CallAfter_wrapper def terminate(): import brailleViewer