diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-23 20:39:17 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-23 20:39:17 +0200 |
| commit | 0c6d43d62cae7815096919239b64891843864896 (patch) | |
| tree | 7f93d3ffde71aba2296de2ecdb15a0d77b519baf /src/mainwindow.cpp | |
| parent | f7948d98fe09c551856b04ba8a473dbd40649dc3 (diff) | |
| download | qtmaildir-0c6d43d62cae7815096919239b64891843864896.tar.gz qtmaildir-0c6d43d62cae7815096919239b64891843864896.zip | |
fix(compose): close every composer when the main window quits
A composer is deliberately parentless, so that it appears in the task
switcher and stays usable while the main window is. Qt therefore does not
take it down with that window, and being a live top-level it kept the process
alive: the main window vanished, the composer stayed on screen with nothing
behind it, and closing it then raised the unsaved-edits dialog for a session
the user had already ended.
The quit path already ASKED about those edits and saved them. What it never
did was close the windows afterwards.
Closing rather than deleting: WA_DeleteOnClose is set on every composer, so
close() is what frees them, and it lets ComposeWindow::closeEvent() run its
own draft handling on the way out. Iterating a copy of the list, since
closing runs the `closed` handler and that mutates m_composers.
Placed last, after every route that turns back has returned: reaching it means
the application really is quitting.
The test opens TWO composers, so a fix that closed only the last one cannot
pass it. Mutation-checked by removing the loop.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q2koFevoSxTLhfexJTZWQd
Diffstat (limited to 'src/mainwindow.cpp')
| -rw-r--r-- | src/mainwindow.cpp | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 0131959..9a94a2e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -422,6 +422,33 @@ void MainWindow::closeEvent(QCloseEvent *event) } } + // Every composer goes with the window, and this is the LAST thing before + // the close is accepted: every route that turns back (Cancel, a failed + // sync, a refused save) has already returned above, so reaching here means + // the application really is quitting. + // + // A composer is deliberately parentless, so that it appears in the task + // switcher and stays usable while the main window is. Qt therefore does not + // take it down with this window, and it kept the process alive: the main + // window vanished, the composer stayed on screen with nothing behind it, + // and closing it then raised the unsaved-edits dialog for a session that + // had already ended. + // + // Closing rather than deleting. WA_DeleteOnClose is set on every composer, + // so close() is what frees them, and it lets ComposeWindow::closeEvent() + // run its own draft handling on the way out. The drafts have already been + // saved by the dialogs above, so that pass has nothing left to do; going + // through it anyway keeps ONE exit path rather than a second one that has + // to be kept in step. + // + // Iterating a COPY: closing a composer runs the `closed` handler, which + // mutates m_composers, and mutating a container mid-iteration is undefined. + const QList<QPointer<ComposeWindow>> composers = m_composers; + for (const QPointer<ComposeWindow> &composer : composers) { + if (composer) + composer->close(); + } + saveUiState(); QMainWindow::closeEvent(event); } |
