From e56b2d7a9e1a762edaf6c34748a4bd2f63648069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 17 Jun 2022 13:29:55 +0200 Subject: iOS: Send touch events asynchronously to avoid deadlocking UIKit event loop Although CFRunLoop is documented to support nesting, the UIKit event delivery machinery is not prepared to handle nested event loops. If the user starts a nested event loop in response to e.g. a button press/release, it will deadlock the entire UIKit event machinery, stopping processing of both screen updates (CATransactions) as well as other events. This became an issue on iPhone hardware device in iOS 15, but can not be reproduces on iPads or in the simulator. To be on the safe side, we deliver all touch events asynchronously, even if that means the application code will always be one step behind the event delivered by the operating system. Fixes: QTBUG-98651 Pick-to: 6.4 6.3 6.2 5.15 Change-Id: Id0a9fa60b7bb7aa98606d46257e99eac144a1080 Reviewed-by: Timur Pocheptsov Reviewed-by: Richard Moe Gustavsen Reviewed-by: Volker Hilsheimer --- src/plugins/platforms/ios/quiview.mm | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index eac492044c..32f27587c6 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -430,7 +430,10 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") QWindowSystemInterface::handleTouchEvent( self.platformWindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values()); } else { - QWindowSystemInterface::handleTouchEvent( + // Send the touch event asynchronously, as the application might spin a recursive + // event loop in response to the touch event (a dialog e.g.), which will deadlock + // the UIKit event delivery system (QTBUG-98651). + QWindowSystemInterface::handleTouchEvent( self.platformWindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values()); } } @@ -536,7 +539,12 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") NSTimeInterval timestamp = event ? event.timestamp : [[NSProcessInfo processInfo] systemUptime]; QIOSIntegration *iosIntegration = static_cast(QGuiApplicationPrivate::platformIntegration()); - QWindowSystemInterface::handleTouchCancelEvent(self.platformWindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice()); + + // Send the touch event asynchronously, as the application might spin a recursive + // event loop in response to the touch event (a dialog e.g.), which will deadlock + // the UIKit event delivery system (QTBUG-98651). + QWindowSystemInterface::handleTouchCancelEvent( + self.platformWindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice()); } - (int)mapPressTypeToKey:(UIPress*)press withModifiers:(Qt::KeyboardModifiers)qtModifiers text:(QString &)text -- cgit v1.2.3