Skip to content

Commit cdeeddf

Browse files
authored
Merge bfe71f5 into bfbe2bf
2 parents bfbe2bf + bfe71f5 commit cdeeddf

4 files changed

Lines changed: 86 additions & 41 deletions

File tree

source/core.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -294,18 +294,23 @@ def triggerNVDAExit(newNVDA: Optional[NewNVDAInstance] = None) -> bool:
294294
instance information with `newNVDA`.
295295
@return: True if this is the first call to trigger the exit, and the shutdown event was queued.
296296
"""
297+
from gui.message import isInMessageBox
297298
import queueHandler
298299
global _hasShutdownBeenTriggered
299300
with _shuttingDownFlagLock:
300-
if not _hasShutdownBeenTriggered:
301+
safeToExit = not isInMessageBox()
302+
if not safeToExit:
303+
log.error("NVDA cannot exit safely, ensure open dialogs are closed")
304+
return False
305+
elif _hasShutdownBeenTriggered:
306+
log.debug("NVDA has already been triggered to exit safely.")
307+
return False
308+
else:
301309
# queue this so that the calling process can exit safely (eg a Popup menu)
302310
queueHandler.queueFunction(queueHandler.eventQueue, _doShutdown, newNVDA)
303311
_hasShutdownBeenTriggered = True
304312
log.debug("_doShutdown has been queued")
305313
return True
306-
else:
307-
log.debug("NVDA has already been triggered to exit safely.")
308-
return False
309314

310315

311316
def _closeAllWindows():

source/gui/__init__.py

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@
2424
import queueHandler
2525
import core
2626
from . import guiHelper
27+
from buildVersion import version_year
28+
from .message import (
29+
isInMessageBox as _isInMessageBox,
30+
# messageBox is accessed through `gui.messageBox` as opposed to `gui.message.messageBox` throughout NVDA,
31+
# be cautious when removing
32+
messageBox,
33+
)
2734
from .settingsDialogs import (
2835
SettingsDialog,
2936
DefaultDictionaryDialog,
@@ -50,7 +57,13 @@
5057

5158
### Globals
5259
mainFrame = None
53-
isInMessageBox = False
60+
61+
if version_year < 2022:
62+
def __getattr__(name):
63+
if name == "isInMessageBox":
64+
log.warning("gui.isInMessageBox is deprecated and will be removed in 2022.1. Consult the changes for developers in 2022.1 for advice on alternatives.")
65+
return _isInMessageBox()
66+
raise AttributeError(f"module {__name__} has no attribute {name}")
5467

5568

5669
class MainFrame(wx.Frame):
@@ -145,7 +158,7 @@ def onSaveConfigurationCommand(self,evt):
145158
messageBox(_("Could not save configuration - probably read only file system"),_("Error"),wx.OK | wx.ICON_ERROR)
146159

147160
def _popupSettingsDialog(self, dialog, *args, **kwargs):
148-
if isInMessageBox:
161+
if _isInMessageBox():
149162
return
150163
self.prePopup()
151164
try:
@@ -194,6 +207,8 @@ def evaluateUpdatePendingUpdateMenuItemCommand(self):
194207
self.sysTrayIcon.menu.Insert(self.sysTrayIcon.installPendingUpdateMenuItemPos,self.sysTrayIcon.installPendingUpdateMenuItem)
195208

196209
def onExitCommand(self, evt):
210+
if _isInMessageBox():
211+
return
197212
if config.conf["general"]["askToExit"]:
198213
self.prePopup()
199214
d = ExitDialog(self)
@@ -295,7 +310,7 @@ def onPythonConsoleCommand(self, evt):
295310
pythonConsole.activate()
296311

297312
def onAddonsManagerCommand(self,evt):
298-
if isInMessageBox:
313+
if _isInMessageBox():
299314
return
300315
self.prePopup()
301316
from .addonGui import AddonsDialog
@@ -311,7 +326,7 @@ def onReloadPluginsCommand(self, evt):
311326
NVDAObject.clearDynamicClassCache()
312327

313328
def onCreatePortableCopyCommand(self,evt):
314-
if isInMessageBox:
329+
if _isInMessageBox():
315330
return
316331
self.prePopup()
317332
import gui.installerGui
@@ -320,15 +335,15 @@ def onCreatePortableCopyCommand(self,evt):
320335
self.postPopup()
321336

322337
def onInstallCommand(self, evt):
323-
if isInMessageBox:
338+
if _isInMessageBox():
324339
return
325340
from gui import installerGui
326341
installerGui.showInstallGui()
327342

328343
def onRunCOMRegistrationFixesCommand(self, evt):
329-
if isInMessageBox:
344+
if _isInMessageBox():
330345
return
331-
if gui.messageBox(
346+
if messageBox(
332347
# Translators: A message to warn the user when starting the COM Registration Fixing tool
333348
_("You are about to run the COM Registration Fixing tool. This tool will try to fix common system problems that stop NVDA from being able to access content in many programs including Firefox and Internet Explorer. This tool must make changes to the System registry and therefore requires administrative access. Are you sure you wish to proceed?"),
334349
# Translators: The title of the warning dialog displayed when launching the COM Registration Fixing tool
@@ -360,7 +375,7 @@ def onRunCOMRegistrationFixesCommand(self, evt):
360375
)
361376

362377
def onConfigProfilesCommand(self, evt):
363-
if isInMessageBox:
378+
if _isInMessageBox():
364379
return
365380
self.prePopup()
366381
from .configProfiles import ProfilesDialog
@@ -574,32 +589,6 @@ def showGui():
574589
def quit():
575590
wx.CallAfter(mainFrame.onExitCommand, None)
576591

577-
def messageBox(message, caption=wx.MessageBoxCaptionStr, style=wx.OK | wx.CENTER, parent=None):
578-
"""Display a message dialog.
579-
This should be used for all message dialogs
580-
rather than using C{wx.MessageDialog} and C{wx.MessageBox} directly.
581-
@param message: The message text.
582-
@type message: str
583-
@param caption: The caption (title) of the dialog.
584-
@type caption: str
585-
@param style: Same as for wx.MessageBox.
586-
@type style: int
587-
@param parent: The parent window (optional).
588-
@type parent: C{wx.Window}
589-
@return: Same as for wx.MessageBox.
590-
@rtype: int
591-
"""
592-
global isInMessageBox
593-
wasAlready = isInMessageBox
594-
isInMessageBox = True
595-
if not parent:
596-
mainFrame.prePopup()
597-
res = wx.MessageBox(message, caption, style, parent or mainFrame)
598-
if not parent:
599-
mainFrame.postPopup()
600-
if not wasAlready:
601-
isInMessageBox = False
602-
return res
603592

604593
def runScriptModalDialog(dialog, callback=None):
605594
"""Run a modal dialog from a script.
@@ -687,9 +676,12 @@ def onOk(self, evt):
687676
action += 1
688677
if action == 0:
689678
WelcomeDialog.closeInstances()
690-
if not core.triggerNVDAExit():
679+
if core.triggerNVDAExit():
680+
# there's no need to destroy ExitDialog in this instance as triggerNVDAExit will do this
681+
return
682+
else:
691683
log.error("NVDA already in process of exiting, this indicates a logic error.")
692-
return # there's no need to destroy ExitDialog in this instance as triggerNVDAExit will do this
684+
return
693685
elif action == 1:
694686
queueHandler.queueFunction(queueHandler.eventQueue,core.restart)
695687
elif action == 2:

source/gui/message.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# -*- coding: UTF-8 -*-
2+
# A part of NonVisual Desktop Access (NVDA)
3+
# Copyright (C) 2006-2021 NV Access Limited, Peter Vágner, Aleksey Sadovoy, Mesar Hameed, Joseph Lee,
4+
# Thomas Stivers, Babbage B.V., Accessolutions, Julien Cochuyt
5+
# This file is covered by the GNU General Public License.
6+
# See the file COPYING for more details.
7+
8+
import threading
9+
from typing import Optional
10+
import wx
11+
12+
_messageBoxCounterLock = threading.Lock()
13+
_messageBoxCounter = 0
14+
15+
16+
def isInMessageBox() -> bool:
17+
return _messageBoxCounter != 0
18+
19+
20+
def messageBox(
21+
message: str,
22+
caption: str = wx.MessageBoxCaptionStr,
23+
style: int = wx.OK | wx.CENTER,
24+
parent: Optional[wx.Window] = None
25+
) -> int:
26+
"""Display a message dialog.
27+
This should be used for all message dialogs
28+
rather than using C{wx.MessageDialog} and C{wx.MessageBox} directly.
29+
@param message: The message text.
30+
@param caption: The caption (title) of the dialog.
31+
@param style: Same as for wx.MessageBox.
32+
@param parent: The parent window.
33+
@return: Same as for wx.MessageBox.
34+
"""
35+
from gui import mainFrame
36+
global _messageBoxCounter
37+
with _messageBoxCounterLock:
38+
_messageBoxCounter += 1
39+
try:
40+
if not parent:
41+
mainFrame.prePopup()
42+
res = wx.MessageBox(message, caption, style, parent or mainFrame)
43+
if not parent:
44+
mainFrame.postPopup()
45+
finally:
46+
with _messageBoxCounterLock:
47+
_messageBoxCounter -= 1
48+
return res

tests/system/robot/startupShutdownNVDA.robot

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ Quits from keyboard with welcome dialog open
4545
Quits from keyboard with about dialog open
4646
[Documentation] Starts NVDA and ensures that it can be quit with the about dialog open
4747
[Setup] start NVDA standard-dontShowWelcomeDialog.ini
48-
# Excluded to be fixed still (#12907, #12957)
48+
# Excluded to be fixed still (#12976)
4949
[Tags] excluded_from_build
5050
open about dialog from menu
5151
quits from keyboard # run test

0 commit comments

Comments
 (0)