Skip to content

Exit NVDA safely by closing all top level windows#12183

Merged
seanbudd merged 29 commits into
masterfrom
fix-12153
Mar 25, 2021
Merged

Exit NVDA safely by closing all top level windows#12183
seanbudd merged 29 commits into
masterfrom
fix-12153

Conversation

@seanbudd

@seanbudd seanbudd commented Mar 16, 2021

Copy link
Copy Markdown
Member

Link to issue number:

closes #12153, #1740

Summary of the issue:

Silent installs of NVDA were causing a crash at the end of the install process.

Upon further investigation it was found NVDA closes the wxApp by exiting the MainLoop. This is not recommended and the behaviour of closing the TopWindow is recommended.

Description of how this pull request fixes the issue:

Adds nvda_crash.dmp from the install process to AppVeyor artifacts for easier testing in future.

Create gui.safeAppExit that

  1. Closes all open dialogs and windows
  2. Forcibly close the main frame window, which will finally exit the app

From wxWidget docs

Call this to explicitly exit the main message (event) loop.

You should normally exit the main loop (and the application) by deleting the top window.

This function simply calls wxEvtLoopBase::Exit() on the active loop

Testing strategy:

Check the various ways of closing and restarting NVDA:

  • through the installation processes
  • through the exit dialog
  • exiting the process as a developer

Confirm the crash dump exists nvda_crash.dmp on this AppVeyor build and the build fails (https://ci.appveyor.com/project/NVAccess/nvda/builds/38282501)

Known issues with pull request:

None

Change log entry:

Changes

- NVDA will exit even with windows still open, the exit process now closes all NVDA windows and dialogs (#1740)

Code Review Checklist:

  • Pull Request description is up to date.
  • Unit tests
  • System (end to end) tests.
  • Manual tests.
  • User Documentation.
  • Change log entry.
  • Context sensitive help for GUI changes.

@seanbudd seanbudd added this to the 2021.1 milestone Mar 16, 2021
@seanbudd seanbudd self-assigned this Mar 16, 2021
@AppVeyorBot

This comment has been minimized.

@seanbudd seanbudd force-pushed the fix-12153 branch 2 times, most recently from 2c8d29c to 79c989b Compare March 16, 2021 07:07
@AppVeyorBot

This comment has been minimized.

@AppVeyorBot

This comment has been minimized.

@AppVeyorBot

This comment has been minimized.

@AppVeyorBot

This comment has been minimized.

@AppVeyorBot

This comment has been minimized.

@AppVeyorBot

This comment has been minimized.

@seanbudd seanbudd changed the title WIP - Exit properly on Appveyor Exit properly on silent install Mar 18, 2021
@AppVeyorBot

This comment has been minimized.

@seanbudd seanbudd marked this pull request as ready for review March 18, 2021 04:15
@AppVeyorBot

This comment has been minimized.

@seanbudd seanbudd marked this pull request as draft March 23, 2021 01:16
@AppVeyorBot

Copy link
Copy Markdown

See test results for failed build of commit bd474b6be6

@seanbudd seanbudd marked this pull request as ready for review March 23, 2021 03:01
@feerrenrut

Copy link
Copy Markdown
Contributor

I think it probably still makes sense to have a helper function for shutting down the application. It allows us to more easily change the shutdown procedure and to track errors such as being called repetitively.

The docs advise using wx.window.close rather than destroy. Destroy is called by close, but is the "more forceful" method.

@seanbudd

Copy link
Copy Markdown
Member Author

I think it probably still makes sense to have a helper function for shutting down the application. It allows us to more easily change the shutdown procedure and to track errors such as being called repetitively.

I agree, I have moved the function yet again to be top level in gui. The destruction of the mainFrame would class the desctruction of the systray icon, which would destroy the systray menu. This process missed other dialog windows such as the WelcomeDialog which would prevent an exit.

The docs advise using wx.window.close rather than destroy. Destroy is called by close, but is the "more forceful" method.

We bind the ExitDialog to EVT_CLOSE so we can't use mainFrame.Close to close the window. (https://github.com/nvaccess/nvda/blob/fc6b73f/source/gui/__init__.py#L55)

https://stackoverflow.com/a/10837130

Comment thread source/gui/__init__.py
Comment thread source/gui/__init__.py
@seanbudd seanbudd linked an issue Mar 25, 2021 that may be closed by this pull request
@seanbudd seanbudd changed the title Exit properly on silent install Exit NVDA safely by closing all top level windows Mar 25, 2021
@feerrenrut

Copy link
Copy Markdown
Contributor

We bind the ExitDialog to EVT_CLOSE so we can't use mainFrame.Close to close the window. >(https://github.com/nvaccess/nvda/blob/fc6b73f/source/gui/__init__.py#L55)

This is binding to the event on the "main frame". These events "bubble upwards" to parent controls if not handled or a handler calls evt.skip(). So yes, I guess they would get there. Close is used because it allows windows to veto, eg if they want to ask to save or similar. If we are confident that none of the locations we are calling from should make use of this, then destroy is fine. Actually, it is probable scope creep to consider it. Maybe just add a line to the docstring that this intentionally doesn't use close, and implementation for a veto-able shutdown procedure will need to be done from scratch and consider how MainFrame.onExitCommand(self, evt) interacts.

@seanbudd seanbudd merged commit 8665526 into master Mar 25, 2021
@seanbudd seanbudd deleted the fix-12153 branch March 25, 2021 08:05
seanbudd added a commit that referenced this pull request Apr 22, 2021
Summary of the issue:
When restarting NVDA, WM_QUIT is posted as an event to the window, forcibly exiting the app. This leaves objects such as the system tray icon left behind.

Additionally, changes introduced in #12183
- caused the braille viewer to be closed without saving state properly
- lost code that destroyed the system tray and menu in some instances
- made most of gui.terminate no longer necessary/redundant

Description of how this pull request fixes the issue:
- A windows event winUser.WM_EXIT_NVDA is registered that triggers safeAppExit and can be called across instances of NVDA.
- move the safe destruction of the brailleviewer to safeAppExit so that it is exited properly before destruction
- reintroduce the destruction of the system tray icon and menu, and remove the icon manually.
- ensured safeAppExit is not called from gui.terminate if it has been called elsewhere to terminate the app. WM_QUIT is the other way to exit the MainLoop other than safeAppExit
- removed restarting the MainLoop in gui.terminate to process pending events as this doesn't work.

Known issues with pull request:
- When starting a new instance of NVDA with an existing instance running, where one is version <2020.4, NVDA will not exit safely. Instead, the running NVDA copy will terminate directly using the behaviour of 2020.4. This is because WM_EXIT_NVDA won't be registered on the older instance.
- Issues with terminating NVDA across instances cannot be logged properly as the loghandler hasn't been initialized
seanbudd added a commit that referenced this pull request May 7, 2021
Summary of the issue:

Changes introduced in #12183

- caused the braille viewer to be closed without saving state properly
- lost code that destroyed the system tray and menu in some instances
- made most of gui.terminate no longer necessary/redundant

Description of how this pull request fixes the issue:

- Creates `core.triggerNVDAExit` which terminates necessary modules safely and then closes all windows
- Destroys the system tray icon and menu
- Uses a parser error message if a new NVDA instance fails to end a running instance. 
- Uses an enum for ChangeWindowMessageFilter filters. 

Known issues with pull request:
WM_QUIT will not exit the app safely (called from a new NVDA instance) when a dialog such as WelcomeDialog is still open
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python 3.8: NVDA fails to exit properly after silent install on AppVeyor Can't quit NVDA while modal dialog is open

5 participants