macOS: Don't leak QEventDispatcherUNIX during event dispatcher creation

During QCoreApplication initialization, we create the main thread's event
dispatcher, which for a GUI app happens via QGuiApplicationPrivate's
createEventDispatcher() override. This in turn relies on the platform
integration to create the event dispatcher, but to do that it needs to
create the platform integration first. And this might result in calling
APIs that themselves initialize the main thread event dispatcher, such
as QEventLoop, which non-lazily creates an event dispatcher for the thread.

We already had a check to catch the platform integration setting the
QCoreApplictionPrivate::eventDispatcher member, but not anything for
checking the current thread data.

On macOS this resulted in a leak of QEventDispatcherUNIX because
QCocoaDrag contained a QEventLoop member. We now track the event
loop temproarily via a pointer instead, like we do in other places.

An alternative fix would be to defer the initialization of QCocoaDrag
until QCocoaIntegration::drag() is called, but that would run the
risk of something calling the function during platform initialization
and we'd be back to the same problem.

It's unclear why QEventLoop is not lazily ensuring the event dispatcher,
and this might be a wider fix for similar issues.

Change-Id: I643010ddb09945936ce9b0b94de0df96f6fe218f
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
(cherry picked from commit 41608170502a08b054a7a244034334d9f4c9ba11)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Tor Arne Vestbø 2023-04-28 13:39:52 +02:00 committed by Qt Cherry-pick Bot
parent 9244018577
commit 8a35934362
3 changed files with 12 additions and 5 deletions

View File

@ -1523,7 +1523,11 @@ void QGuiApplicationPrivate::createEventDispatcher()
if (platform_integration == nullptr)
createPlatformIntegration();
// The platform integration should not mess with the event dispatcher
// The platform integration should not result in creating an event dispatcher
Q_ASSERT_X(!threadData.loadRelaxed()->eventDispatcher, "QGuiApplication",
"Creating the platform integration resulted in creating an event dispatcher");
// Nor should it mess with the QCoreApplication's event dispatcher
Q_ASSERT(!eventDispatcher);
eventDispatcher = platform_integration->createEventDispatcher();

View File

@ -44,7 +44,7 @@ private:
NSEvent *m_lastEvent;
NSView *m_lastView;
Qt::DropAction m_executed_drop_action;
QEventLoop internalDragLoop;
QEventLoop *m_internalDragLoop = nullptr;
bool maybeDragMultipleItems();

View File

@ -213,7 +213,9 @@ bool QCocoaDrag::maybeDragMultipleItems()
}
[sourceView beginDraggingSessionWithItems:dragItems event:m_lastEvent source:sourceView];
internalDragLoop.exec();
QEventLoop eventLoop;
QScopedValueRollback updateGuard(m_internalDragLoop, &eventLoop);
eventLoop.exec();
return true;
}
@ -224,8 +226,9 @@ void QCocoaDrag::setAcceptedAction(Qt::DropAction act)
void QCocoaDrag::exitDragLoop()
{
if (internalDragLoop.isRunning())
internalDragLoop.exit();
Q_ASSERT(m_internalDragLoop);
if (m_internalDragLoop->isRunning())
m_internalDragLoop->exit();
}