Emit aboutToQuit from QCoreApplication::exit() instead of execCleanup()

The aboutToQuit signal is documented to be emitted "when the application
is about to quit the main event loop", which is useful "if your application
has to do some last-second cleanup", and is recommended over "putting it in
your application's main() function because on some platforms the exec() call
may not return".

However, if we're on a platform where the exec call may not return, it
will be because the event dispatcher's exec doesn't return, which means
we'll never get out of the call to eventLoop.exec(QEventLoop::ApplicationExec)
and into the execCleanup() code.

In addition, on macOS, where we do currently return to main(), we do so
by telling the platform to cancel the application termination, by returning
NSTerminateCancel from applicationShouldTerminate, after running the quit
logic of Qt via QWindowSystemInterface::handleApplicationTermination().
In the case of quitting applications due to system logout/shutdown, this
cancellation brings up a dialog saying the Qt application interrupted the
process, which luckily disappears again as soon as the application
actually terminates via main(). Moving the emit of aboutToQuit() earlier
in the flow, before we've cancelled the application termination, reduces
the chance that long running code triggered from this signal will keep the
dialog visible to the user.

Task-number: QTBUG-102321
Change-Id: I362737e9563069fc02b1e9639e1251d655d13949
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
Tor Arne Vestbø 2022-10-11 17:19:11 +02:00
parent d84ddf5905
commit 449b45ff34

View File

@ -1363,9 +1363,6 @@ void QCoreApplicationPrivate::execCleanup()
{
threadData.loadRelaxed()->quitNow = false;
in_exec = false;
if (!aboutToQuitEmitted)
emit q_func()->aboutToQuit(QCoreApplication::QPrivateSignal());
aboutToQuitEmitted = true;
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
}
@ -1404,7 +1401,12 @@ void QCoreApplication::exit(int returnCode)
{
if (!self)
return;
QThreadData *data = self->d_func()->threadData.loadRelaxed();
QCoreApplicationPrivate *d = self->d_func();
if (!d->aboutToQuitEmitted) {
emit self->aboutToQuit(QCoreApplication::QPrivateSignal());
d->aboutToQuitEmitted = true;
}
QThreadData *data = d->threadData.loadRelaxed();
data->quitNow = true;
for (qsizetype i = 0; i < data->eventLoops.size(); ++i) {
QEventLoop *eventLoop = data->eventLoops.at(i);