summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/ios/quiview.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/ios/quiview.mm')
-rw-r--r--src/plugins/platforms/ios/quiview.mm88
1 files changed, 80 insertions, 8 deletions
diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm
index 406bfcf5b3..dda8ee5b53 100644
--- a/src/plugins/platforms/ios/quiview.mm
+++ b/src/plugins/platforms/ios/quiview.mm
@@ -43,6 +43,7 @@
#include "qiosintegration.h"
#include "qiosviewcontroller.h"
#include "qiostextresponder.h"
+#include "qiosscreen.h"
#include "qioswindow.h"
#ifndef Q_OS_TVOS
#include "qiosmenu.h"
@@ -56,6 +57,24 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
@implementation QUIView
++ (void)load
+{
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 11)) {
+ // iOS 11 handles this though [UIView safeAreaInsetsDidChange], but there's no signal for
+ // the corresponding top and bottom layout guides that we use on earlier versions. Note
+ // that we use the _will_ change version of the notification, because we want to react
+ // to the change as early was possible. But since the top and bottom layout guides have
+ // not been updated at this point we use asynchronous delivery of the event, so that the
+ // event is processed by QtGui just after iOS has updated the layout margins.
+ [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillChangeStatusBarFrameNotification
+ object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *) {
+ for (QWindow *window : QGuiApplication::allWindows())
+ QWindowSystemInterface::handleSafeAreaMarginsChanged<QWindowSystemInterface::AsynchronousDelivery>(window);
+ }
+ ];
+ }
+}
+
+ (Class)layerClass
{
return [CAEAGLLayer class];
@@ -100,6 +119,22 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
self.layer.borderColor = colorWithBrightness(1.0);
self.layer.borderWidth = 1.0;
}
+
+#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, 110000, 110000, __WATCHOS_NA)
+ if (qEnvironmentVariableIsSet("QT_IOS_DEBUG_WINDOW_SAFE_AREAS")) {
+ if (__builtin_available(iOS 11, tvOS 11, *)) {
+ UIView *safeAreaOverlay = [[UIView alloc] initWithFrame:CGRectZero];
+ [safeAreaOverlay setBackgroundColor:[UIColor colorWithRed:0.3 green:0.7 blue:0.9 alpha:0.3]];
+ [self addSubview:safeAreaOverlay];
+
+ safeAreaOverlay.translatesAutoresizingMaskIntoConstraints = NO;
+ [safeAreaOverlay.topAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor].active = YES;
+ [safeAreaOverlay.leftAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.leftAnchor].active = YES;
+ [safeAreaOverlay.rightAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.rightAnchor].active = YES;
+ [safeAreaOverlay.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor].active = YES;
+ }
+ }
+#endif
}
return self;
@@ -163,7 +198,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
QRect lastReportedGeometry = qt_window_private(window)->geometry;
QRect currentGeometry = QRectF::fromCGRect(self.frame).toRect();
qCDebug(lcQpaWindow) << m_qioswindow->window() << "new geometry is" << currentGeometry;
- QWindowSystemInterface::handleGeometryChange<QWindowSystemInterface::SynchronousDelivery>(window, currentGeometry);
+ QWindowSystemInterface::handleGeometryChange(window, currentGeometry);
if (currentGeometry.size() != lastReportedGeometry.size()) {
// Trigger expose event on resize
@@ -196,7 +231,12 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
}
qCDebug(lcQpaWindow) << m_qioswindow->window() << region << "isExposed" << m_qioswindow->isExposed();
- QWindowSystemInterface::handleExposeEvent<QWindowSystemInterface::SynchronousDelivery>(m_qioswindow->window(), region);
+ QWindowSystemInterface::handleExposeEvent(m_qioswindow->window(), region);
+}
+
+- (void)safeAreaInsetsDidChange
+{
+ QWindowSystemInterface::handleSafeAreaMarginsChanged(m_qioswindow->window());
}
// -------------------------------------------------------------------------
@@ -227,7 +267,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
}
if (qGuiApp->focusWindow() != m_qioswindow->window())
- QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(m_qioswindow->window());
+ QWindowSystemInterface::handleWindowActivated(m_qioswindow->window());
else
qImDebug() << m_qioswindow->window() << "already active, not sending window activation";
@@ -265,7 +305,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
UIResponder *newResponder = FirstResponderCandidate::currentCandidate();
if ([self responderShouldTriggerWindowDeactivation:newResponder])
- QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(0);
+ QWindowSystemInterface::handleWindowActivated(0);
return YES;
}
@@ -384,8 +424,24 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
}
}
}
- if (!m_activeTouches.isEmpty())
- QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
+ if (m_activeTouches.isEmpty())
+ return;
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
+ if (!static_cast<QUIWindow *>(self.window).sendingEvent) {
+ // The event is likely delivered as part of delayed touch delivery, via
+ // _UIGestureEnvironmentSortAndSendDelayedTouches, due to one of the two
+ // _UISystemGestureGateGestureRecognizer instances on the top level window
+ // having its delaysTouchesBegan set to YES. During this delivery, it's not
+ // safe to spin up a recursive event loop, as our calling function is not
+ // reentrant, so any gestures used by the recursive code, e.g. a native
+ // alert dialog, will fail to recognize. To be on the safe side, we deliver
+ // the event asynchronously.
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::AsynchronousDelivery>(
+ m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
+ } else {
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
+ m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
+ }
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
@@ -483,7 +539,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
NSTimeInterval timestamp = event ? event.timestamp : [[NSProcessInfo processInfo] systemUptime];
QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
- QWindowSystemInterface::handleTouchCancelEvent<QWindowSystemInterface::SynchronousDelivery>(m_qioswindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice());
+ QWindowSystemInterface::handleTouchCancelEvent(m_qioswindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice());
}
- (int)mapPressTypeToKey:(UIPress*)press
@@ -511,7 +567,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
int key = [self mapPressTypeToKey:press];
if (key == Qt::Key_unknown)
continue;
- if (QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(m_qioswindow->window(), type, key, Qt::NoModifier))
+ if (QWindowSystemInterface::handleKeyEvent(m_qioswindow->window(), type, key, Qt::NoModifier))
handled = true;
}
@@ -590,6 +646,22 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
return nil;
}
+- (UIEdgeInsets)qt_safeAreaInsets
+{
+#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, 110000, 110000, __WATCHOS_NA)
+ if (__builtin_available(iOS 11, tvOS 11, *))
+ return self.safeAreaInsets;
+#endif
+
+ // Fallback for iOS < 11
+ UIEdgeInsets safeAreaInsets = UIEdgeInsetsZero;
+ CGPoint topInset = [self convertPoint:CGPointMake(0, self.viewController.topLayoutGuide.length) fromView:nil];
+ CGPoint bottomInset = [self convertPoint:CGPointMake(0, self.viewController.bottomLayoutGuide.length) fromView:nil];
+ safeAreaInsets.top = topInset.y;
+ safeAreaInsets.bottom = bottomInset.y;
+ return safeAreaInsets;
+}
+
@end
#ifndef QT_NO_ACCESSIBILITY