aboutsummaryrefslogtreecommitdiffstats
path: root/src/quickwidgets/qquickwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quickwidgets/qquickwidget.cpp')
-rw-r--r--src/quickwidgets/qquickwidget.cpp109
1 files changed, 76 insertions, 33 deletions
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index e914d8d6b3..c782dc74b1 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;
@@ -335,8 +360,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 +423,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 +628,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 +651,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 +674,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 +1011,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 +1025,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 +1040,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 +1081,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 +1129,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());
@@ -1462,6 +1491,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 +1508,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 +1573,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 +1587,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 +1681,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 +1705,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 +1721,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();