summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Arne Vestbø <[email protected]>2023-08-17 18:03:33 +0200
committerTor Arne Vestbø <[email protected]>2023-08-18 17:01:28 +0200
commit17e7d98626b21e55d1ca8eb638859e025bf0ec9a (patch)
tree894357c6155e8d2513643ca1fb70888ff8bc16af
parent199570e3b1e7b3a6db64be29d9b5889e29cd8a01 (diff)
iOS: Add support for foreign windows
Task-number: QTBUG-116183 Pick-to: 6.6 Change-Id: Ia92ee2d15f2e91a326ad342237fb0a83305c019f Reviewed-by: Timur Pocheptsov <[email protected]>
-rw-r--r--src/corelib/kernel/qcore_mac_p.h14
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.h10
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h1
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm7
-rw-r--r--src/plugins/platforms/ios/qioswindow.h6
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm54
6 files changed, 69 insertions, 23 deletions
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index 58326dbd568..1b0283e77bd 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -441,6 +441,20 @@ private:
// -------------------------------------------------------------------------
+#ifdef __OBJC__
+template <typename T>
+typename std::enable_if<std::is_pointer<T>::value, T>::type
+qt_objc_cast(id object)
+{
+ if ([object isKindOfClass:[typename std::remove_pointer<T>::type class]])
+ return static_cast<T>(object);
+
+ return nil;
+}
+#endif
+
+// -------------------------------------------------------------------------
+
QT_END_NAMESPACE
#endif // QCORE_MAC_P_H
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h
index 694e57e73df..0fcda72b4d4 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.h
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.h
@@ -56,16 +56,6 @@ NSDragOperation qt_mac_mapDropActions(Qt::DropActions actions);
Qt::DropAction qt_mac_mapNSDragOperation(NSDragOperation nsActions);
Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions);
-template <typename T>
-typename std::enable_if<std::is_pointer<T>::value, T>::type
-qt_objc_cast(id object)
-{
- if ([object isKindOfClass:[typename std::remove_pointer<T>::type class]])
- return static_cast<T>(object);
-
- return nil;
-}
-
QT_MANGLE_NAMESPACE(QNSView) *qnsview_cast(NSView *view);
// Misc
diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h
index 3de1fb4c57e..a57a707c7f4 100644
--- a/src/plugins/platforms/ios/qiosintegration.h
+++ b/src/plugins/platforms/ios/qiosintegration.h
@@ -31,6 +31,7 @@ public:
bool hasCapability(Capability cap) const override;
QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override;
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
#if QT_CONFIG(opengl)
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index 44aeaabec20..c646042eb26 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -150,6 +150,8 @@ bool QIOSIntegration::hasCapability(Capability cap) const
return false;
case ApplicationState:
return true;
+ case ForeignWindows:
+ return true;
default:
return QPlatformIntegration::hasCapability(cap);
}
@@ -160,6 +162,11 @@ QPlatformWindow *QIOSIntegration::createPlatformWindow(QWindow *window) const
return new QIOSWindow(window);
}
+QPlatformWindow *QIOSIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const
+{
+ return new QIOSWindow(window, nativeHandle);
+}
+
QPlatformBackingStore *QIOSIntegration::createPlatformBackingStore(QWindow *window) const
{
return new QRhiBackingStore(window);
diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h
index 6a50ccfbcec..762a31af9a2 100644
--- a/src/plugins/platforms/ios/qioswindow.h
+++ b/src/plugins/platforms/ios/qioswindow.h
@@ -21,7 +21,7 @@ class QIOSWindow : public QObject, public QPlatformWindow
Q_OBJECT
public:
- explicit QIOSWindow(QWindow *window);
+ explicit QIOSWindow(QWindow *window, WId nativeHandle = 0);
~QIOSWindow();
void setGeometry(const QRect &rect) override;
@@ -66,7 +66,7 @@ private:
void applicationStateChanged(Qt::ApplicationState state);
void applyGeometry(const QRect &rect);
- QUIView *m_view;
+ UIView *m_view;
QRect m_normalGeometry;
int m_windowLevel;
@@ -82,6 +82,8 @@ private:
QDebug operator<<(QDebug debug, const QIOSWindow *window);
#endif
+QT_MANGLE_NAMESPACE(QUIView) *quiview_cast(UIView *view);
+
QT_END_NAMESPACE
#endif // QIOSWINDOW_H
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index 908ead2e5d2..3f1a15f854e 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -29,19 +29,24 @@
QT_BEGIN_NAMESPACE
-QIOSWindow::QIOSWindow(QWindow *window)
+QIOSWindow::QIOSWindow(QWindow *window, WId nativeHandle)
: QPlatformWindow(window)
, m_windowLevel(0)
{
+ if (nativeHandle) {
+ m_view = reinterpret_cast<UIView *>(nativeHandle);
+ [m_view retain];
+ } else {
#ifdef Q_OS_IOS
- if (window->surfaceType() == QSurface::RasterSurface)
- window->setSurfaceType(QSurface::MetalSurface);
+ if (window->surfaceType() == QSurface::RasterSurface)
+ window->setSurfaceType(QSurface::MetalSurface);
- if (window->surfaceType() == QSurface::MetalSurface)
- m_view = [[QUIMetalView alloc] initWithQIOSWindow:this];
- else
+ if (window->surfaceType() == QSurface::MetalSurface)
+ m_view = [[QUIMetalView alloc] initWithQIOSWindow:this];
+ else
#endif
- m_view = [[QUIView alloc] initWithQIOSWindow:this];
+ m_view = [[QUIView alloc] initWithQIOSWindow:this];
+ }
connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QIOSWindow::applicationStateChanged);
@@ -80,7 +85,7 @@ QIOSWindow::~QIOSWindow()
clearAccessibleCache();
- m_view.platformWindow = 0;
+ quiview_cast(m_view).platformWindow = 0;
[m_view removeFromSuperview];
[m_view release];
}
@@ -120,7 +125,7 @@ void QIOSWindow::setVisible(bool visible)
if (visible && shouldAutoActivateWindow()) {
if (!window()->property("_q_showWithoutActivating").toBool())
requestActivateWindow();
- } else if (!visible && [m_view isActiveWindow]) {
+ } else if (!visible && [quiview_cast(m_view) isActiveWindow]) {
// Our window was active/focus window but now hidden, so relinquish
// focus to the next possible window in the stack.
NSArray<UIView *> *subviews = m_view.viewController.view.subviews;
@@ -340,8 +345,11 @@ void QIOSWindow::handleContentOrientationChange(Qt::ScreenOrientation orientatio
void QIOSWindow::applicationStateChanged(Qt::ApplicationState)
{
+ if (isForeignWindow())
+ return;
+
if (window()->isExposed() != isExposed())
- [m_view sendUpdatedExposeEvent];
+ [quiview_cast(m_view) sendUpdatedExposeEvent];
}
qreal QIOSWindow::devicePixelRatio() const
@@ -351,7 +359,10 @@ qreal QIOSWindow::devicePixelRatio() const
void QIOSWindow::clearAccessibleCache()
{
- [m_view clearAccessibleCache];
+ if (isForeignWindow())
+ return;
+
+ [quiview_cast(m_view) clearAccessibleCache];
}
void QIOSWindow::requestUpdate()
@@ -394,6 +405,27 @@ QDebug operator<<(QDebug debug, const QIOSWindow *window)
}
#endif // !QT_NO_DEBUG_STREAM
+/*!
+ Returns the view cast to a QUIview if possible.
+
+ If the view is not a QUIview, nil is returned, which is safe to
+ send messages to, effectively making [quiview_cast(view) message]
+ a no-op.
+
+ For extra verbosity and clearer code, please consider checking
+ that the platform window is not a foreign window before using
+ this cast, via QPlatformWindow::isForeignWindow().
+
+ Do not use this method solely to check for foreign windows, as
+ that will make the code harder to read for people not working
+ primarily on iOS, who do not know the difference between the
+ UIView and QUIView cases.
+*/
+QUIView *quiview_cast(UIView *view)
+{
+ return qt_objc_cast<QUIView *>(view);
+}
+
QT_END_NAMESPACE
#include "moc_qioswindow.cpp"