diff options
Diffstat (limited to 'src/quickwidgets')
-rw-r--r-- | src/quickwidgets/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/quickwidgets/qaccessiblequickwidget.cpp | 30 | ||||
-rw-r--r-- | src/quickwidgets/qaccessiblequickwidget_p.h | 6 | ||||
-rw-r--r-- | src/quickwidgets/qquickwidget.cpp | 119 | ||||
-rw-r--r-- | src/quickwidgets/qquickwidget_p.h | 4 |
5 files changed, 109 insertions, 51 deletions
diff --git a/src/quickwidgets/CMakeLists.txt b/src/quickwidgets/CMakeLists.txt index aa7a682343..f3575c84fc 100644 --- a/src/quickwidgets/CMakeLists.txt +++ b/src/quickwidgets/CMakeLists.txt @@ -33,7 +33,6 @@ qt_internal_add_module(QuickWidgets Qt::QmlPrivate Qt::QuickPrivate Qt::WidgetsPrivate - GENERATE_CPP_EXPORTS ) qt_internal_extend_target(QuickWidgets CONDITION QT_FEATURE_accessibility diff --git a/src/quickwidgets/qaccessiblequickwidget.cpp b/src/quickwidgets/qaccessiblequickwidget.cpp index f67d3eecab..40b8f8daf2 100644 --- a/src/quickwidgets/qaccessiblequickwidget.cpp +++ b/src/quickwidgets/qaccessiblequickwidget.cpp @@ -11,32 +11,52 @@ QT_BEGIN_NAMESPACE QAccessibleQuickWidget::QAccessibleQuickWidget(QQuickWidget* widget) : QAccessibleWidget(widget) -, m_accessibleWindow(QQuickWidgetPrivate::get(widget)->offscreenWindow) { // NOTE: m_accessibleWindow is a QAccessibleQuickWindow, and not a // QAccessibleQuickWidgetOffscreenWindow (defined below). This means // it will return the Quick item child interfaces, which is what's needed here // (unlike QAccessibleQuickWidgetOffscreenWindow, which will report 0 children). + repairWindow(); +} + +QAccessibleQuickWidget::~QAccessibleQuickWidget() +{ + QObject::disconnect(m_connection); +} + +void QAccessibleQuickWidget::repairWindow() +{ + if (!m_accessibleWindow || !m_accessibleWindow->object()) { + QQuickWidget *theWidget = static_cast<QQuickWidget *>(object()); + QQuickWindow *newOffscreen = QQuickWidgetPrivate::get(theWidget)->offscreenWindow; + // We use the qobject_cast here to detect that the newOffscreen is + // not the one getting destroyed right now. + if (qobject_cast<QQuickWindow *>(newOffscreen)) { + m_accessibleWindow.reset(new QAccessibleQuickWindow(newOffscreen)); + m_connection = QObject::connect(newOffscreen, &QObject::destroyed, theWidget, + [this] { repairWindow(); }); + } + } } QAccessibleInterface *QAccessibleQuickWidget::child(int index) const { - return m_accessibleWindow.child(index); + return m_accessibleWindow->child(index); } int QAccessibleQuickWidget::childCount() const { - return m_accessibleWindow.childCount(); + return m_accessibleWindow->childCount(); } int QAccessibleQuickWidget::indexOfChild(const QAccessibleInterface *iface) const { - return m_accessibleWindow.indexOfChild(iface); + return m_accessibleWindow->indexOfChild(iface); } QAccessibleInterface *QAccessibleQuickWidget::childAt(int x, int y) const { - return m_accessibleWindow.childAt(x, y); + return m_accessibleWindow->childAt(x, y); } QAccessibleQuickWidgetOffscreenWindow::QAccessibleQuickWidgetOffscreenWindow(QQuickWindow *window) diff --git a/src/quickwidgets/qaccessiblequickwidget_p.h b/src/quickwidgets/qaccessiblequickwidget_p.h index ea86433c41..a0c99b7d97 100644 --- a/src/quickwidgets/qaccessiblequickwidget_p.h +++ b/src/quickwidgets/qaccessiblequickwidget_p.h @@ -31,6 +31,7 @@ class QAccessibleQuickWidget: public QAccessibleWidget { public: QAccessibleQuickWidget(QQuickWidget* widget); + ~QAccessibleQuickWidget(); QAccessibleInterface *child(int index) const override; int childCount() const override; @@ -38,7 +39,10 @@ public: QAccessibleInterface *childAt(int x, int y) const override; private: - QAccessibleQuickWindow m_accessibleWindow; + void repairWindow(); + + std::unique_ptr<QAccessibleQuickWindow> m_accessibleWindow; + QMetaObject::Connection m_connection; Q_DISABLE_COPY(QAccessibleQuickWidget) }; diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index e914d8d6b3..130b7677e6 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -47,6 +47,10 @@ #include <QtWidgets/qgraphicsview.h> #endif +#if QT_CONFIG(vulkan) +#include <QtGui/private/qvulkandefaultinstance_p.h> +#endif + QT_BEGIN_NAMESPACE QQuickWidgetOffscreenWindow::QQuickWidgetOffscreenWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control) @@ -196,6 +200,27 @@ void QQuickWidgetPrivate::init(QQmlEngine* e) if (!engine.isNull() && !engine.data()->incubationController()) engine.data()->setIncubationController(offscreenWindow->incubationController()); + q->setMouseTracking(true); + q->setFocusPolicy(Qt::StrongFocus); +#ifndef Q_OS_MACOS + /* + Usually, a QTouchEvent comes from a touchscreen, and we want those + touch events in Qt Quick. But on macOS, there are no touchscreens, and + WA_AcceptTouchEvents has a different meaning: QApplication::notify() + calls the native-integration function registertouchwindow() to change + NSView::allowedTouchTypes to include NSTouchTypeMaskIndirect when the + trackpad cursor enters the window, and removes that mask when the + cursor exits. In other words, WA_AcceptTouchEvents enables getting + discrete touchpoints from the trackpad. We rather prefer to get mouse, + wheel and native gesture events from the trackpad (because those + provide more of a "native feel"). The only exception is for + MultiPointTouchArea, and it takes care of that for itself. So don't + automatically set WA_AcceptTouchEvents on macOS. The user can still do + it, but we don't recommend it. + */ + q->setAttribute(Qt::WA_AcceptTouchEvents); +#endif + #if QT_CONFIG(quick_draganddrop) q->setAcceptDrops(true); #endif @@ -241,7 +266,7 @@ void QQuickWidgetPrivate::handleWindowChange() // must be recreated because its RHI will contain a dangling pointer to // the context. - delete offscreenWindow; + QScopedPointer<QQuickWindow> oldOffScreenWindow(offscreenWindow); // Do not delete before reparenting sgItem offscreenWindow = nullptr; delete renderControl; @@ -251,9 +276,7 @@ void QQuickWidgetPrivate::handleWindowChange() QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate())); QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate())); - if (!source.isEmpty()) - execute(); - else if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(root)) + if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(root)) sgItem->setParentItem(offscreenWindow->contentItem()); } @@ -335,8 +358,10 @@ void QQuickWidgetPrivate::render(bool needsSync) q->createFramebufferObject(); } - if (!rhi) + if (!rhi) { + qWarning("QQuickWidget: Attempted to render scene with no rhi"); return; + } // createFramebufferObject() bails out when the size is empty. In this case // we cannot render either. @@ -396,11 +421,6 @@ void QQuickWidgetPrivate::renderSceneGraph() if (!q->isVisible() || fakeHidden) return; - if (!useSoftwareRenderer && !rhi) { - qWarning("QQuickWidget: Attempted to render scene with no rhi"); - return; - } - render(true); #if QT_CONFIG(graphicsview) @@ -606,24 +626,22 @@ QImage QQuickWidgetPrivate::grabFramebuffer() */ /*! - Constructs a QQuickWidget with the given \a parent. - The default value of \a parent is 0. + Constructs a QQuickWidget with a default QML engine as a child of \a parent. + The default value of \a parent is \c nullptr. */ QQuickWidget::QQuickWidget(QWidget *parent) : QWidget(*(new QQuickWidgetPrivate), parent, {}) { - setMouseTracking(true); - setFocusPolicy(Qt::StrongFocus); - setAttribute(Qt::WA_AcceptTouchEvents); d_func()->init(); } /*! - Constructs a QQuickWidget with the given QML \a source and \a parent. - The default value of \a parent is 0. + Constructs a QQuickWidget with a default QML engine and the given QML \a source + as a child of \a parent. -*/ + The default value of \a parent is \c nullptr. + */ QQuickWidget::QQuickWidget(const QUrl &source, QWidget *parent) : QQuickWidget(parent) { @@ -631,19 +649,15 @@ QQuickWidget::QQuickWidget(const QUrl &source, QWidget *parent) } /*! - Constructs a QQuickWidget with the given QML \a engine and \a parent. + Constructs a QQuickWidget with the given QML \a engine as a child of \a parent. - Note: In this case, the QQuickWidget does not own the given \a engine object; + \note The QQuickWidget does not take ownership of the given \a engine object; it is the caller's responsibility to destroy the engine. If the \a engine is deleted - before the view, status() will return QQuickWidget::Error. - - \sa Status, status(), errors() + before the view, \l status() will return \l QQuickWidget::Error. */ QQuickWidget::QQuickWidget(QQmlEngine* engine, QWidget *parent) : QWidget(*(new QQuickWidgetPrivate), parent, {}) { - setMouseTracking(true); - setFocusPolicy(Qt::StrongFocus); d_func()->init(engine); } @@ -658,6 +672,9 @@ QQuickWidget::~QQuickWidget() delete d->root; d->root = nullptr; + if (d->rhi) + d->rhi->removeCleanupCallback(this); + // NB! resetting graphics resources must be done from this destructor, // *not* from the private class' destructor. This is due to how destruction // works and due to the QWidget dtor (for toplevels) destroying the repaint @@ -992,6 +1009,8 @@ static inline QPlatformBackingStoreRhiConfig::Api graphicsApiToBackingStoreRhiAp return QPlatformBackingStoreRhiConfig::Vulkan; case QSGRendererInterface::Direct3D11: return QPlatformBackingStoreRhiConfig::D3D11; + case QSGRendererInterface::Direct3D12: + return QPlatformBackingStoreRhiConfig::D3D12; case QSGRendererInterface::Metal: return QPlatformBackingStoreRhiConfig::Metal; default: @@ -1004,13 +1023,10 @@ void QQuickWidgetPrivate::initializeWithRhi() { Q_Q(QQuickWidget); - QWidgetPrivate *tlwd = QWidgetPrivate::get(q->window()); // when reparenting, the rhi may suddenly be different if (rhi) { - QRhi *tlwRhi = nullptr; - if (QWidgetRepaintManager *repaintManager = tlwd->maybeRepaintManager()) - tlwRhi = repaintManager->rhi(); - if (tlwRhi && rhi != tlwRhi) + QRhi *backingStoreRhi = QWidgetPrivate::rhi(); + if (backingStoreRhi && rhi != backingStoreRhi) rhi = nullptr; } @@ -1022,8 +1038,17 @@ void QQuickWidgetPrivate::initializeWithRhi() if (rhi) return; - if (QWidgetRepaintManager *repaintManager = tlwd->maybeRepaintManager()) - rhi = repaintManager->rhi(); + if (QRhi *backingStoreRhi = QWidgetPrivate::rhi()) { + rhi = backingStoreRhi; + // We don't own the RHI, so make sure we clean up if it goes away + rhi->addCleanupCallback(q, [this](QRhi *rhi) { + if (this->rhi == rhi) { + invalidateRenderControl(); + deviceLost = true; + this->rhi = nullptr; + } + }); + } if (!rhi) { // The widget (and its parent chain, if any) may not be shown at @@ -1054,6 +1079,8 @@ void QQuickWidgetPrivate::initializeWithRhi() #if QT_CONFIG(vulkan) if (QWindow *w = q->window()->windowHandle()) offscreenWindow->setVulkanInstance(w->vulkanInstance()); + else if (rhi == offscreenRenderer.rhi()) + offscreenWindow->setVulkanInstance(QVulkanDefaultInstance::instance()); #endif renderControl->initialize(); } @@ -1100,7 +1127,7 @@ void QQuickWidget::createFramebufferObject() // Could be a simple hide - show, in which case the previous texture is just fine. if (!d->outputTexture) { - d->outputTexture = d->rhi->newTexture(QRhiTexture::RGBA8, fboSize, 1, QRhiTexture::RenderTarget); + d->outputTexture = d->rhi->newTexture(QRhiTexture::RGBA8, fboSize, 1, QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource); if (!d->outputTexture->create()) { qWarning("QQuickWidget: failed to create output texture of size %dx%d", fboSize.width(), fboSize.height()); @@ -1284,12 +1311,6 @@ QPlatformBackingStoreRhiConfig QQuickWidgetPrivate::rhiConfig() const QWidgetPrivate::TextureData QQuickWidgetPrivate::texture() const { - Q_Q(const QQuickWidget); - if (!q->isWindow() && q->internalWinId()) { - qWarning() << "QQuickWidget cannot be used as a native child widget." - << "Consider setting Qt::AA_DontCreateNativeWidgetSiblings"; - return {}; - } return { outputTexture, nullptr }; } @@ -1462,6 +1483,8 @@ void QQuickWidget::mouseMoveEvent(QMouseEvent *e) // top-level window always. QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(), e->button(), e->buttons(), e->modifiers(), e->source()); + // It's not just the timestamp but also the globalPressPosition, velocity etc. + mappedEvent.setTimestamp(e->timestamp()); QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent); e->setAccepted(mappedEvent.isAccepted()); } @@ -1477,10 +1500,12 @@ void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e) // See QTBUG-25831 QMouseEvent pressEvent(QEvent::MouseButtonPress, e->position(), e->position(), e->globalPosition(), e->button(), e->buttons(), e->modifiers(), e->source()); + pressEvent.setTimestamp(e->timestamp()); QCoreApplication::sendEvent(d->offscreenWindow, &pressEvent); e->setAccepted(pressEvent.isAccepted()); QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(), e->button(), e->buttons(), e->modifiers(), e->source()); + mappedEvent.setTimestamp(e->timestamp()); QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent); } @@ -1540,6 +1565,7 @@ void QQuickWidget::mousePressEvent(QMouseEvent *e) QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(), e->button(), e->buttons(), e->modifiers(), e->source()); + mappedEvent.setTimestamp(e->timestamp()); QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent); e->setAccepted(mappedEvent.isAccepted()); } @@ -1553,6 +1579,7 @@ void QQuickWidget::mouseReleaseEvent(QMouseEvent *e) QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(), e->button(), e->buttons(), e->modifiers(), e->source()); + mappedEvent.setTimestamp(e->timestamp()); QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent); e->setAccepted(mappedEvent.isAccepted()); } @@ -1646,7 +1673,7 @@ bool QQuickWidget::event(QEvent *e) QPointerEvent *pointerEvent = static_cast<QPointerEvent *>(e); auto deliveredPoints = pointerEvent->points(); for (auto &point : deliveredPoints) { - if (pointerEvent->exclusiveGrabber(point)) + if (pointerEvent->exclusiveGrabber(point) || !pointerEvent->passiveGrabbers(point).isEmpty()) point.setAccepted(true); } } @@ -1670,7 +1697,10 @@ bool QQuickWidget::event(QEvent *e) } case QEvent::WindowAboutToChangeInternal: + if (d->rhi) + d->rhi->removeCleanupCallback(this); d->invalidateRenderControl(); + d->deviceLost = true; d->rhi = nullptr; break; @@ -1683,15 +1713,20 @@ bool QQuickWidget::event(QEvent *e) QScreen *newScreen = screen(); if (d->offscreenWindow) d->offscreenWindow->setScreen(newScreen); - + break; + } + case QEvent::DevicePixelRatioChange: if (d->useSoftwareRenderer || d->outputTexture) { // This will check the size taking the devicePixelRatio into account // and recreate if needed. createFramebufferObject(); d->render(true); } + if (d->offscreenWindow) { + QEvent dprChangeEvent(QEvent::DevicePixelRatioChange); + QGuiApplication::sendEvent(d->offscreenWindow, &dprChangeEvent); + } break; - } case QEvent::Show: case QEvent::Move: d->updatePosition(); diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h index 7167f4fdea..181fbd8d92 100644 --- a/src/quickwidgets/qquickwidget_p.h +++ b/src/quickwidgets/qquickwidget_p.h @@ -17,7 +17,7 @@ #include "qquickwidget.h" #include <private/qwidget_p.h> -#include <private/qrhi_p.h> +#include <rhi/qrhi.h> #include <private/qbackingstorerhisupport_p.h> #include <QtCore/qurl.h> @@ -67,7 +67,7 @@ public: QPlatformTextureList::Flags textureListFlags() override; QImage grabFramebuffer() override; - void init(QQmlEngine* e = 0); + void init(QQmlEngine* e = nullptr); void ensureBackingScene(); void initOffscreenWindow(); void ensureEngine() const; |