aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items')
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp3
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp3
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp13
-rw-r--r--src/quick/items/qquickborderimage.cpp2
-rw-r--r--src/quick/items/qquickdroparea.cpp19
-rw-r--r--src/quick/items/qquickevents.cpp12
-rw-r--r--src/quick/items/qquickflickable.cpp2
-rw-r--r--src/quick/items/qquickgenericshadereffect.cpp18
-rw-r--r--src/quick/items/qquickgraphicsinfo.cpp7
-rw-r--r--src/quick/items/qquickgraphicsinfo_p.h11
-rw-r--r--src/quick/items/qquickgridview.cpp9
-rw-r--r--src/quick/items/qquickimage.cpp2
-rw-r--r--src/quick/items/qquickimagebase.cpp5
-rw-r--r--src/quick/items/qquickitem_p.h13
-rw-r--r--src/quick/items/qquickitemsmodule.cpp2
-rw-r--r--src/quick/items/qquickitemview.cpp48
-rw-r--r--src/quick/items/qquickitemview_p_p.h6
-rw-r--r--src/quick/items/qquickitemviewfxitem.cpp2
-rw-r--r--src/quick/items/qquickitemviewfxitem_p_p.h2
-rw-r--r--src/quick/items/qquickitemviewtransition.cpp20
-rw-r--r--src/quick/items/qquickitemviewtransition_p.h2
-rw-r--r--src/quick/items/qquicklistview.cpp17
-rw-r--r--src/quick/items/qquickmousearea.cpp4
-rw-r--r--src/quick/items/qquickopenglshadereffect.cpp11
-rw-r--r--src/quick/items/qquickopenglshadereffect_p.h2
-rw-r--r--src/quick/items/qquickopenglshadereffectnode.cpp3
-rw-r--r--src/quick/items/qquickopenglshadereffectnode_p.h2
-rw-r--r--src/quick/items/qquickpathview.cpp8
-rw-r--r--src/quick/items/qquickrectangle.cpp26
-rw-r--r--src/quick/items/qquickrendercontrol.cpp13
-rw-r--r--src/quick/items/qquickrepeater.cpp9
-rw-r--r--src/quick/items/qquickshadereffect.cpp34
-rw-r--r--src/quick/items/qquickshadereffect_p.h1
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp2
-rw-r--r--src/quick/items/qquickspriteengine.cpp12
-rw-r--r--src/quick/items/qquickspriteengine_p.h4
-rw-r--r--src/quick/items/qquickspritesequence_p.h1
-rw-r--r--src/quick/items/qquickspritesequence_p_p.h3
-rw-r--r--src/quick/items/qquicktableview.cpp15
-rw-r--r--src/quick/items/qquicktextcontrol.cpp46
-rw-r--r--src/quick/items/qquicktextcontrol_p.h7
-rw-r--r--src/quick/items/qquicktextcontrol_p_p.h3
-rw-r--r--src/quick/items/qquicktextedit.cpp31
-rw-r--r--src/quick/items/qquicktextedit_p.h4
-rw-r--r--src/quick/items/qquicktextedit_p_p.h3
-rw-r--r--src/quick/items/qquicktextinput.cpp7
-rw-r--r--src/quick/items/qquicktextnode.cpp2
-rw-r--r--src/quick/items/qquickview.cpp17
-rw-r--r--src/quick/items/qquickwindow.cpp361
-rw-r--r--src/quick/items/qquickwindow.h10
-rw-r--r--src/quick/items/qquickwindow_p.h18
-rw-r--r--src/quick/items/qquickwindowmodule.cpp1
52 files changed, 696 insertions, 182 deletions
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index 188e74cd89..ac4e86d8da 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -769,7 +769,8 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
if (!node) {
- node = QQuickWindowPrivate::get(window())->context->sceneGraphContext()->createInternalImageNode();
+ QSGRenderContext *rc = QQuickWindowPrivate::get(window())->context;
+ node = rc->sceneGraphContext()->createInternalImageNode(rc);
d->node = node;
}
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 0f104a122f..48e5a4d4a2 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -4290,7 +4290,8 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_renderTarget = QQuickCanvasItem::Image;
}
- // Disable Framebuffer Object based rendering when not running with OpenGL
+ // Disable Framebuffer Object based rendering when not running with OpenGL.
+ // Same goes for the RHI based code path (regardless of the backend in use).
if (m_renderTarget == QQuickCanvasItem::FramebufferObject) {
QSGRendererInterface *rif = canvasItem->window()->rendererInterface();
if (rif && rif->graphicsApi() != QSGRendererInterface::OpenGL)
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index 69ff3b3852..0ebd1a66c9 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -41,7 +41,7 @@
#include "qquickcontext2dtile_p.h"
#include "qquickcanvasitem_p.h"
#include <private/qquickitem_p.h>
-#include <QtQuick/private/qsgtexture_p.h>
+#include <QtQuick/private/qsgplaintexture_p.h>
#include "qquickcontext2dcommandbuffer_p.h"
#include <QOpenGLPaintDevice>
#if QT_CONFIG(opengl)
@@ -238,15 +238,8 @@ void QQuickContext2DTexture::paintWithoutTiles(QQuickContext2DCommandBuffer *ccb
QPainter p;
p.begin(device);
- if (m_antialiasing)
- p.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing | QPainter::TextAntialiasing, true);
- else
- p.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing | QPainter::TextAntialiasing, false);
-
- if (m_smooth)
- p.setRenderHint(QPainter::SmoothPixmapTransform, true);
- else
- p.setRenderHint(QPainter::SmoothPixmapTransform, false);
+ p.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing, m_antialiasing);
+ p.setRenderHint(QPainter::SmoothPixmapTransform, m_smooth);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index b840328184..c53a39ca09 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -647,7 +647,7 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
bool updatePixmap = d->pixmapChanged;
d->pixmapChanged = false;
if (!node) {
- node = d->sceneGraphContext()->createInternalImageNode();
+ node = d->sceneGraphContext()->createInternalImageNode(d->sceneGraphRenderContext());
updatePixmap = true;
}
diff --git a/src/quick/items/qquickdroparea.cpp b/src/quick/items/qquickdroparea.cpp
index 4f6afb1863..f96d6b6244 100644
--- a/src/quick/items/qquickdroparea.cpp
+++ b/src/quick/items/qquickdroparea.cpp
@@ -43,6 +43,8 @@
#include <private/qv4arraybuffer_p.h>
+#include <QtCore/qregularexpression.h>
+
QT_BEGIN_NAMESPACE
QQuickDropAreaDrag::QQuickDropAreaDrag(QQuickDropAreaPrivate *d, QObject *parent)
@@ -68,7 +70,7 @@ public:
QStringList getKeys(const QMimeData *mimeData) const;
QStringList keys;
- QRegExp keyRegExp;
+ QRegularExpression keyRegExp;
QPointF dragPosition;
QQuickDropAreaDrag *drag;
QPointer<QObject> source;
@@ -155,13 +157,15 @@ void QQuickDropArea::setKeys(const QStringList &keys)
d->keys = keys;
if (keys.isEmpty()) {
- d->keyRegExp = QRegExp();
+ d->keyRegExp = QRegularExpression();
} else {
- QString pattern = QLatin1Char('(') + QRegExp::escape(keys.first());
+ QString pattern = QLatin1Char('(') + QRegularExpression::escape(keys.first());
for (int i = 1; i < keys.count(); ++i)
- pattern += QLatin1Char('|') + QRegExp::escape(keys.at(i));
+ pattern += QLatin1Char('|') + QRegularExpression::escape(keys.at(i));
pattern += QLatin1Char(')');
- d->keyRegExp = QRegExp(pattern.replace(QLatin1String("\\*"), QLatin1String(".+")));
+ d->keyRegExp = QRegularExpression(
+ QRegularExpression::anchoredPattern(pattern.replace(QLatin1String("\\*"),
+ QLatin1String(".+"))));
}
emit keysChanged();
}
@@ -229,12 +233,11 @@ void QQuickDropArea::dragMoveEvent(QDragMoveEvent *event)
bool QQuickDropAreaPrivate::hasMatchingKey(const QStringList &keys) const
{
- if (keyRegExp.isEmpty())
+ if (keyRegExp.pattern().isEmpty())
return true;
- QRegExp copy = keyRegExp;
for (const QString &key : keys) {
- if (copy.exactMatch(key))
+ if (key.contains(keyRegExp))
return true;
}
return false;
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 28b217b7b3..51c662cb3a 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -851,7 +851,7 @@ void QQuickEventPoint::setGrabberItem(QQuickItem *grabber)
if (oldGrabberHandler && !oldGrabberHandler->approveGrabTransition(this, grabber))
return;
if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
- qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this) << "@" << m_scenePos
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this) << "@" << m_scenePos
<< ": grab" << m_exclusiveGrabber << "->" << grabber;
}
QQuickItem *oldGrabberItem = grabberItem();
@@ -892,10 +892,10 @@ void QQuickEventPoint::setGrabberPointerHandler(QQuickPointerHandler *grabber, b
if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
if (exclusive) {
if (m_exclusiveGrabber != grabber)
- qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this)
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this)
<< ": grab (exclusive)" << m_exclusiveGrabber << "->" << grabber;
} else {
- qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this)
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this)
<< ": grab (passive)" << grabber;
}
}
@@ -954,7 +954,7 @@ void QQuickEventPoint::cancelExclusiveGrabImpl(QTouchEvent *cancelEvent)
if (m_exclusiveGrabber.isNull())
return;
if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
- qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this)
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this)
<< ": grab (exclusive)" << m_exclusiveGrabber << "-> nullptr";
}
if (auto handler = grabberPointerHandler()) {
@@ -977,7 +977,7 @@ void QQuickEventPoint::cancelPassiveGrab(QQuickPointerHandler *handler)
{
if (removePassiveGrabber(handler)) {
if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
- qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this)
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this)
<< ": grab (passive)" << handler << "removed";
}
handler->onGrabChanged(handler, CancelGrabPassive, this);
@@ -1956,7 +1956,7 @@ Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *eve
dbg << "QQuickEventPoint(accepted:" << event->isAccepted()
<< " state:";
QtDebugUtils::formatQEnum(dbg, event->state());
- dbg << " scenePos:" << event->scenePosition() << " id:" << hex << event->pointId() << dec
+ dbg << " scenePos:" << event->scenePosition() << " id:" << Qt::hex << event->pointId() << Qt::dec
<< " timeHeld:" << event->timeHeld() << ')';
return dbg;
}
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index d6dddc3f1c..7e1f54f07e 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -206,8 +206,8 @@ public:
axisData->move.setValue(-flickable->contentX());
else
axisData->move.setValue(-flickable->contentY());
- cancel();
active = false;
+ cancel();
}
protected:
diff --git a/src/quick/items/qquickgenericshadereffect.cpp b/src/quick/items/qquickgenericshadereffect.cpp
index 3e7eda28eb..1d71555849 100644
--- a/src/quick/items/qquickgenericshadereffect.cpp
+++ b/src/quick/items/qquickgenericshadereffect.cpp
@@ -44,11 +44,11 @@
QT_BEGIN_NAMESPACE
-// The generic shader effect is used when the scenegraph backend indicates
-// SupportsShaderEffectNode. This, unlike the monolithic and interconnected (e.g.
-// with particles) OpenGL variant, passes most of the work to a scenegraph node
-// created via the adaptation layer, thus allowing different implementation in
-// the backends.
+// The generic shader effect is used whenever on the RHI code path, or when the
+// scenegraph backend indicates SupportsShaderEffectNode. This, unlike the
+// monolithic and interconnected (e.g. with particles) OpenGL variant, passes
+// most of the work to a scenegraph node created via the adaptation layer, thus
+// allowing different implementation in the backends.
QQuickGenericShaderEffect::QQuickGenericShaderEffect(QQuickShaderEffect *item, QObject *parent)
: QObject(parent)
@@ -254,6 +254,10 @@ QSGNode *QQuickGenericShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQui
if (!node) {
QSGRenderContext *rc = QQuickWindowPrivate::get(m_item->window())->context;
node = rc->sceneGraphContext()->createShaderEffectNode(rc, mgr);
+ if (!node) {
+ qWarning("No shader effect node");
+ return nullptr;
+ }
m_dirty = QSGShaderEffectNode::DirtyShaderAll;
}
@@ -445,7 +449,7 @@ bool QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray
// provided and monitored like with an application-provided shader.
QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
v.name = QByteArrayLiteral("source");
- v.bindPoint = 0;
+ v.bindPoint = 0; // fake
v.type = texturesSeparate ? QSGGuiThreadShaderEffectManager::ShaderInfo::Texture
: QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler;
m_shaders[shaderType].shaderInfo.variables.append(v);
@@ -559,7 +563,7 @@ QT_WARNING_POP
} else {
// Do not warn for dynamic properties.
if (!m_item->property(v.name.constData()).isValid())
- qWarning("ShaderEffect: '%s' does not have a matching property!", v.name.constData());
+ qWarning("ShaderEffect: '%s' does not have a matching property", v.name.constData());
}
vd.value = m_item->property(v.name.constData());
diff --git a/src/quick/items/qquickgraphicsinfo.cpp b/src/quick/items/qquickgraphicsinfo.cpp
index cd1012c690..8f6f4386fb 100644
--- a/src/quick/items/qquickgraphicsinfo.cpp
+++ b/src/quick/items/qquickgraphicsinfo.cpp
@@ -96,6 +96,12 @@ QQuickGraphicsInfo *QQuickGraphicsInfo::qmlAttachedProperties(QObject *object)
\li GraphicsInfo.Software - Qt Quick's software renderer based on QPainter with the raster paint engine
\li GraphicsInfo.OpenGL - OpenGL or OpenGL ES
\li GraphicsInfo.Direct3D12 - Direct3D 12
+ \li GraphicsInfo.OpenVG - OpenVG
+ \li GraphicsInfo.OpenGLRhi - OpenGL on top of QRhi, a graphics abstraction layer
+ \li GraphicsInfo.Direct3D11Rhi - Direct3D 11 on top of QRhi, a graphics abstraction layer
+ \li GraphicsInfo.VulkanRhi - Vulkan on top of QRhi, a graphics abstraction layer
+ \li GraphicsInfo.MetalRhi - Metal on top of QRhi, a graphics abstraction layer
+ \li GraphicsInfo.NullRhi - Null (no output) on top of QRhi, a graphics abstraction layer
\endlist
*/
@@ -109,6 +115,7 @@ QQuickGraphicsInfo *QQuickGraphicsInfo::qmlAttachedProperties(QObject *object)
\li GraphicsInfo.UnknownShadingLanguage - Not yet known due to no window and scenegraph associated
\li GraphicsInfo.GLSL - GLSL or GLSL ES
\li GraphicsInfo.HLSL - HLSL
+ \li GraphicsInfo.RhiShader - QShader
\endlist
\note The value is only up-to-date once the item is associated with a
diff --git a/src/quick/items/qquickgraphicsinfo_p.h b/src/quick/items/qquickgraphicsinfo_p.h
index 9ef7bacb3e..f0a18c29cc 100644
--- a/src/quick/items/qquickgraphicsinfo_p.h
+++ b/src/quick/items/qquickgraphicsinfo_p.h
@@ -80,14 +80,21 @@ public:
Unknown = QSGRendererInterface::Unknown,
Software = QSGRendererInterface::Software,
OpenGL = QSGRendererInterface::OpenGL,
- Direct3D12 = QSGRendererInterface::Direct3D12
+ Direct3D12 = QSGRendererInterface::Direct3D12,
+ OpenVG = QSGRendererInterface::OpenVG,
+ OpenGLRhi = QSGRendererInterface::OpenGLRhi,
+ Direct3D11Rhi = QSGRendererInterface::Direct3D11Rhi,
+ VulkanRhi = QSGRendererInterface::VulkanRhi,
+ MetalRhi = QSGRendererInterface::MetalRhi,
+ NullRhi = QSGRendererInterface::NullRhi
};
Q_ENUM(GraphicsApi)
enum ShaderType {
UnknownShadingLanguage = QSGRendererInterface::UnknownShadingLanguage,
GLSL = QSGRendererInterface::GLSL,
- HLSL = QSGRendererInterface::HLSL
+ HLSL = QSGRendererInterface::HLSL,
+ RhiShader = QSGRendererInterface::RhiShader
};
Q_ENUM(ShaderType)
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index 6638fbd3e8..fecfa5fd2d 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -191,7 +191,7 @@ public:
void resetFirstItemPosition(qreal pos = 0.0) override;
void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible) override;
- void createHighlight() override;
+ void createHighlight(bool onDestruction = false) override;
void updateHighlight() override;
void resetHighlightPosition() override;
@@ -696,9 +696,8 @@ void QQuickGridViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int
gridItem->setPosition(gridItem->colPos(), gridItem->rowPos() + ((moveCount / columns) * rowSize()));
}
-void QQuickGridViewPrivate::createHighlight()
+void QQuickGridViewPrivate::createHighlight(bool onDestruction)
{
- Q_Q(QQuickGridView);
bool changed = false;
if (highlight) {
if (trackedItem == highlight)
@@ -714,6 +713,10 @@ void QQuickGridViewPrivate::createHighlight()
changed = true;
}
+ if (onDestruction)
+ return;
+
+ Q_Q(QQuickGridView);
if (currentItem) {
QQuickItem *item = createHighlightItem();
if (item) {
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 4a0936b4d5..dfbe271606 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -663,7 +663,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
if (!node) {
d->pixmapChanged = true;
- node = d->sceneGraphContext()->createInternalImageNode();
+ node = d->sceneGraphContext()->createInternalImageNode(d->sceneGraphRenderContext());
}
QRectF targetRect;
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index 74ee859f77..729d326625 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -46,6 +46,8 @@
#include <QtQml/qqmlinfo.h>
#include <QtQml/qqmlfile.h>
+#include <QtQml/qqmlabstracturlinterceptor.h>
+
QT_BEGIN_NAMESPACE
@@ -244,6 +246,9 @@ void QQuickImageBase::load()
d->devicePixelRatio = 1.0;
QUrl loadUrl = d->url;
+ QQmlEngine* engine = qmlEngine(this);
+ if (engine && engine->urlInterceptor())
+ loadUrl = engine->urlInterceptor()->intercept(loadUrl, QQmlAbstractUrlInterceptor::UrlString);
bool updatedDevicePixelRatio = false;
if (d->sourcesize.isValid())
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 847fd90230..3e8feec4bf 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -75,6 +75,7 @@
#include <QtCore/qlist.h>
#include <QtCore/qdebug.h>
#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qpointer.h>
#if QT_CONFIG(quick_shadereffect)
#include <QtQuick/private/qquickshadereffectsource_p.h>
@@ -687,12 +688,12 @@ public:
: leftSet(false), rightSet(false), upSet(false), downSet(false),
tabSet(false), backtabSet(false) {}
- QQuickItem *left = nullptr;
- QQuickItem *right = nullptr;
- QQuickItem *up = nullptr;
- QQuickItem *down = nullptr;
- QQuickItem *tab = nullptr;
- QQuickItem *backtab = nullptr;
+ QPointer<QQuickItem> left;
+ QPointer<QQuickItem> right;
+ QPointer<QQuickItem> up;
+ QPointer<QQuickItem> down;
+ QPointer<QQuickItem> tab;
+ QPointer<QQuickItem> backtab;
bool leftSet : 1;
bool rightSet : 1;
bool upSet : 1;
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index eaad06e0c4..bc87b2c43f 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -226,6 +226,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickPathCatmullRomCurve>("QtQuick",2,0,"PathCurve");
qmlRegisterType<QQuickPathArc>("QtQuick",2,0,"PathArc");
qmlRegisterType<QQuickPathSvg>("QtQuick",2,0,"PathSvg");
+ qmlRegisterType<QQuickPath, 14>(uri, 2, 14, "Path");
+ qmlRegisterType<QQuickPathPolyline>("QtQuick", 2, 14, "PathPolyline");
#endif
#if QT_CONFIG(quick_pathview)
qmlRegisterType<QQuickPathView>(uri,major,minor,"PathView");
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 1f8a0de72b..95f1229b92 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -162,7 +162,7 @@ QQuickItemView::QQuickItemView(QQuickFlickablePrivate &dd, QQuickItem *parent)
QQuickItemView::~QQuickItemView()
{
Q_D(QQuickItemView);
- d->clear();
+ d->clear(true);
if (d->ownModel)
delete d->model;
delete d->header;
@@ -1662,7 +1662,7 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex)
releaseItem(oldCurrentItem);
}
-void QQuickItemViewPrivate::clear()
+void QQuickItemViewPrivate::clear(bool onDestruction)
{
Q_Q(QQuickItemView);
currentChanges.reset();
@@ -1683,7 +1683,7 @@ void QQuickItemViewPrivate::clear()
currentItem = nullptr;
if (oldCurrentItem)
emit q->currentItemChanged();
- createHighlight();
+ createHighlight(onDestruction);
trackedItem = nullptr;
if (requestedIndex >= 0) {
@@ -1724,8 +1724,14 @@ void QQuickItemViewPrivate::refill()
void QQuickItemViewPrivate::refill(qreal from, qreal to)
{
Q_Q(QQuickItemView);
- if (!isValid() || !q->isComponentComplete())
+ if (!model || !model->isValid() || !q->isComponentComplete())
+ return;
+ if (!model->count()) {
+ updateHeader();
+ updateFooter();
+ updateViewport();
return;
+ }
do {
bufferPause.stop();
@@ -1881,15 +1887,21 @@ void QQuickItemViewPrivate::layout()
prepareVisibleItemTransitions();
- for (QList<FxViewItem*>::Iterator it = releasePendingTransition.begin();
- it != releasePendingTransition.end(); ) {
- FxViewItem *item = *it;
- if (prepareNonVisibleItemTransition(item, viewBounds)) {
- ++it;
- } else {
- releaseItem(item);
+ for (auto it = releasePendingTransition.begin(); it != releasePendingTransition.end(); ) {
+ auto old_count = releasePendingTransition.count();
+ auto success = prepareNonVisibleItemTransition(*it, viewBounds);
+ // prepareNonVisibleItemTransition() may invalidate iterators while in fast flicking
+ // invisible animating items are kicked in or out the viewPort
+ // use old_count to test if the abrupt erasure occurs
+ if (old_count > releasePendingTransition.count()) {
+ continue;
+ }
+ if (!success) {
+ releaseItem(*it);
it = releasePendingTransition.erase(it);
+ continue;
}
+ ++it;
}
for (int i=0; i<visibleItems.count(); i++)
@@ -2232,7 +2244,10 @@ bool QQuickItemViewPrivate::prepareNonVisibleItemTransition(FxViewItem *item, co
if (item->scheduledTransitionType() == QQuickItemViewTransitioner::MoveTransition)
repositionItemAt(item, item->index, 0);
- if (item->prepareTransition(transitioner, viewBounds)) {
+ bool success = false;
+ ACTION_IF_DELETED(item, success = item->prepareTransition(transitioner, viewBounds), return success);
+
+ if (success) {
item->releaseAfterTransition = true;
return true;
}
@@ -2352,15 +2367,16 @@ void QQuickItemView::destroyingItem(QObject *object)
bool QQuickItemViewPrivate::releaseItem(FxViewItem *item)
{
Q_Q(QQuickItemView);
- if (!item || !model)
+ if (!item)
return true;
if (trackedItem == item)
trackedItem = nullptr;
item->trackGeometry(false);
- QQmlInstanceModel::ReleaseFlags flags = model->release(item->item);
- if (item->item) {
- if (flags == 0) {
+ QQmlInstanceModel::ReleaseFlags flags = {};
+ if (model && item->item) {
+ flags = model->release(item->item);
+ if (!flags) {
// item was not destroyed, and we no longer reference it.
QQuickItemPrivate::get(item->item)->setCulled(true);
unrequestedItems.insert(item->item, model->indexOf(item->item, q));
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index 0f1594f904..ef674f0fc7 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -163,7 +163,7 @@ public:
int mapFromModel(int modelIndex) const;
virtual void init();
- virtual void clear();
+ virtual void clear(bool onDestruction=false);
virtual void updateViewport();
void regenerate(bool orientationChanged=false);
@@ -287,7 +287,7 @@ public:
: item(i), moveKey(k) {}
};
QQuickItemViewTransitioner *transitioner;
- QList<FxViewItem *> releasePendingTransition;
+ QVector<FxViewItem *> releasePendingTransition;
mutable qreal minExtent;
mutable qreal maxExtent;
@@ -327,7 +327,7 @@ protected:
virtual bool hasStickyHeader() const { return false; }
virtual bool hasStickyFooter() const { return false; }
- virtual void createHighlight() = 0;
+ virtual void createHighlight(bool onDestruction = false) = 0;
virtual void updateHighlight() = 0;
virtual void resetHighlightPosition() = 0;
virtual bool movingFromHighlight() { return false; }
diff --git a/src/quick/items/qquickitemviewfxitem.cpp b/src/quick/items/qquickitemviewfxitem.cpp
index 60e9d7b115..ead4a030ac 100644
--- a/src/quick/items/qquickitemviewfxitem.cpp
+++ b/src/quick/items/qquickitemviewfxitem.cpp
@@ -56,6 +56,8 @@ QQuickItemViewFxItem::QQuickItemViewFxItem(QQuickItem *item, bool ownItem, QQuic
QQuickItemViewFxItem::~QQuickItemViewFxItem()
{
delete transitionableItem;
+ transitionableItem = nullptr;
+
if (ownItem && item) {
trackGeometry(false);
item->setParentItem(0);
diff --git a/src/quick/items/qquickitemviewfxitem_p_p.h b/src/quick/items/qquickitemviewfxitem_p_p.h
index 3bc5ba440c..3985630cda 100644
--- a/src/quick/items/qquickitemviewfxitem_p_p.h
+++ b/src/quick/items/qquickitemviewfxitem_p_p.h
@@ -54,6 +54,7 @@
#include <QtQuick/private/qtquickglobal_p.h>
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquickitemviewtransition_p.h>
+#include <private/qanimationjobutil_p.h>
QT_REQUIRE_CONFIG(quick_itemview);
@@ -94,6 +95,7 @@ public:
virtual bool contains(qreal x, qreal y) const = 0;
+ SelfDeletable m_selfDeletable;
QPointer<QQuickItem> item;
QQuickItemChangeListener *changeListener;
QQuickItemViewTransitionableItem *transitionableItem;
diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp
index 0fde0beb75..109851608b 100644
--- a/src/quick/items/qquickitemviewtransition.cpp
+++ b/src/quick/items/qquickitemviewtransition.cpp
@@ -61,7 +61,6 @@ public:
QPointF m_toPos;
QQuickItemViewTransitioner::TransitionType m_type;
bool m_isTarget;
- bool *m_wasDeleted;
protected:
void finished() override;
@@ -73,14 +72,11 @@ QQuickItemViewTransitionJob::QQuickItemViewTransitionJob()
, m_item(nullptr)
, m_type(QQuickItemViewTransitioner::NoTransition)
, m_isTarget(false)
- , m_wasDeleted(nullptr)
{
}
QQuickItemViewTransitionJob::~QQuickItemViewTransitionJob()
{
- if (m_wasDeleted)
- *m_wasDeleted = true;
if (m_transitioner)
m_transitioner->runningJobs.remove(this);
}
@@ -138,13 +134,7 @@ void QQuickItemViewTransitionJob::finished()
QQuickTransitionManager::finished();
if (m_transitioner) {
- bool deleted = false;
- m_wasDeleted = &deleted;
- m_transitioner->finishedTransition(this, m_item);
- if (deleted)
- return;
- m_wasDeleted = nullptr;
-
+ RETURN_IF_DELETED(m_transitioner->finishedTransition(this, m_item));
m_transitioner = nullptr;
}
@@ -482,7 +472,7 @@ bool QQuickItemViewTransitionableItem::prepareTransition(QQuickItemViewTransitio
// if transition type is not valid, the previous transition still has to be
// canceled so that the item can move immediately to the right position
item->setPosition(nextTransitionTo);
- stopTransition();
+ ACTION_IF_DELETED(this, stopTransition(), return false);
}
prepared = true;
@@ -501,12 +491,12 @@ void QQuickItemViewTransitionableItem::startTransition(QQuickItemViewTransitione
if (!transition || transition->m_type != nextTransitionType || transition->m_isTarget != isTransitionTarget) {
if (transition)
- transition->cancel();
+ RETURN_IF_DELETED(transition->cancel());
delete transition;
transition = new QQuickItemViewTransitionJob;
}
- transition->startTransition(this, index, transitioner, nextTransitionType, nextTransitionTo, isTransitionTarget);
+ RETURN_IF_DELETED(transition->startTransition(this, index, transitioner, nextTransitionType, nextTransitionTo, isTransitionTarget));
clearCurrentScheduledTransition();
}
@@ -558,7 +548,7 @@ void QQuickItemViewTransitionableItem::clearCurrentScheduledTransition()
void QQuickItemViewTransitionableItem::stopTransition()
{
if (transition)
- transition->cancel();
+ RETURN_IF_DELETED(transition->cancel());
clearCurrentScheduledTransition();
resetNextTransitionPos();
}
diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h
index 29a62f7f10..0c7a9cad75 100644
--- a/src/quick/items/qquickitemviewtransition_p.h
+++ b/src/quick/items/qquickitemviewtransition_p.h
@@ -60,6 +60,7 @@ QT_REQUIRE_CONFIG(quick_viewtransitions);
#include <QtQml/qqml.h>
#include <private/qqmlguard_p.h>
#include <private/qquicktransition_p.h>
+#include <private/qanimationjobutil_p.h>
QT_BEGIN_NAMESPACE
@@ -157,6 +158,7 @@ public:
bool prepareTransition(QQuickItemViewTransitioner *transitioner, int index, const QRectF &viewBounds);
void startTransition(QQuickItemViewTransitioner *transitioner, int index);
+ SelfDeletable m_selfDeletable;
QPointF nextTransitionTo;
QPointF lastMovedTo;
QPointF nextTransitionFrom;
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 81d019a26d..146917c679 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -81,7 +81,7 @@ public:
FxViewItem *snapItemAt(qreal pos);
void init() override;
- void clear() override;
+ void clear(bool onDestruction) override;
bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer) override;
bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) override;
@@ -98,7 +98,7 @@ public:
void adjustFirstItem(qreal forwards, qreal backwards, int) override;
void updateSizeChangesBeforeVisiblePos(FxViewItem *item, ChangeResult *removeResult) override;
- void createHighlight() override;
+ void createHighlight(bool onDestruction = false) override;
void updateHighlight() override;
void resetHighlightPosition() override;
bool movingFromHighlight() override;
@@ -575,7 +575,7 @@ void QQuickListViewPrivate::init()
::memset(sectionCache, 0, sizeof(QQuickItem*) * sectionCacheSize);
}
-void QQuickListViewPrivate::clear()
+void QQuickListViewPrivate::clear(bool onDestruction)
{
for (int i = 0; i < sectionCacheSize; ++i) {
delete sectionCache[i];
@@ -587,7 +587,7 @@ void QQuickListViewPrivate::clear()
releaseSectionItem(nextSectionItem);
nextSectionItem = nullptr;
lastVisibleSection = QString();
- QQuickItemViewPrivate::clear();
+ QQuickItemViewPrivate::clear(onDestruction);
}
FxViewItem *QQuickListViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
@@ -634,7 +634,7 @@ void QQuickListViewPrivate::initializeViewItem(FxViewItem *item)
bool QQuickListViewPrivate::releaseItem(FxViewItem *item)
{
if (!item || !model)
- return true;
+ return QQuickItemViewPrivate::releaseItem(item);
QPointer<QQuickItem> it = item->item;
QQuickListViewAttached *att = static_cast<QQuickListViewAttached*>(item->attached);
@@ -876,9 +876,8 @@ void QQuickListViewPrivate::updateSizeChangesBeforeVisiblePos(FxViewItem *item,
QQuickItemViewPrivate::updateSizeChangesBeforeVisiblePos(item, removeResult);
}
-void QQuickListViewPrivate::createHighlight()
+void QQuickListViewPrivate::createHighlight(bool onDestruction)
{
- Q_Q(QQuickListView);
bool changed = false;
if (highlight) {
if (trackedItem == highlight)
@@ -896,6 +895,10 @@ void QQuickListViewPrivate::createHighlight()
changed = true;
}
+ if (onDestruction)
+ return;
+
+ Q_Q(QQuickListView);
if (currentItem) {
QQuickItem *item = createHighlightItem();
if (item) {
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 53a5e5df1c..bce7ec718b 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -761,8 +761,10 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
QPointF targetPos = d->drag->target()->position();
- if (d->drag->active())
+ if (d->drag->active()) {
d->drag->target()->setPosition(boundedDragPos);
+ d->lastPos = d->lastScenePos - mapToScene(position());
+ }
bool dragOverThresholdX = QQuickWindowPrivate::dragOverThreshold(dragPos.x() - startPos.x(),
Qt::XAxis, event, d->drag->threshold());
diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp
index 0cbabaa170..0fd7df8938 100644
--- a/src/quick/items/qquickopenglshadereffect.cpp
+++ b/src/quick/items/qquickopenglshadereffect.cpp
@@ -57,6 +57,10 @@
QT_BEGIN_NAMESPACE
+// Note: this legacy ShaderEffect implementation is used only when running
+// directly with OpenGL. This is going to go away in the future (Qt 6?), since
+// the RHI path uses QQuickGenericShaderEffect always.
+
namespace {
enum VariableQualifier {
@@ -221,7 +225,7 @@ QQuickOpenGLShaderEffectCommon::~QQuickOpenGLShaderEffectCommon()
clearSignalMappers(shaderType);
}
-void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QObject *obj, Key::ShaderType shaderType)
+void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
{
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
if (signalMappers[shaderType].at(i) == 0)
@@ -229,11 +233,12 @@ void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QObject *obj, Key
const UniformData &d = uniformData[shaderType].at(i);
auto mapper = signalMappers[shaderType].at(i);
void *a = mapper;
- QObjectPrivate::disconnect(obj, mapper->signalIndex(), &a);
+ QObjectPrivate::disconnect(item, mapper->signalIndex(), &a);
if (d.specialType == UniformData::Sampler || d.specialType == UniformData::SamplerExternal) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source) {
- QQuickItemPrivate::get(source)->derefWindow();
+ if (item->window())
+ QQuickItemPrivate::get(source)->derefWindow();
QObject::disconnect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*)));
}
}
diff --git a/src/quick/items/qquickopenglshadereffect_p.h b/src/quick/items/qquickopenglshadereffect_p.h
index 3087c1eb0b..0c2adadc62 100644
--- a/src/quick/items/qquickopenglshadereffect_p.h
+++ b/src/quick/items/qquickopenglshadereffect_p.h
@@ -89,7 +89,7 @@ struct Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectCommon
~QQuickOpenGLShaderEffectCommon();
- void disconnectPropertySignals(QObject *item, Key::ShaderType shaderType);
+ void disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
void connectPropertySignals(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType);
void updateParseLog(bool ignoreAttributes);
void lookThroughShaderCode(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType, const QByteArray &code);
diff --git a/src/quick/items/qquickopenglshadereffectnode.cpp b/src/quick/items/qquickopenglshadereffectnode.cpp
index f96ebebcd6..26ef59c20e 100644
--- a/src/quick/items/qquickopenglshadereffectnode.cpp
+++ b/src/quick/items/qquickopenglshadereffectnode.cpp
@@ -366,7 +366,6 @@ class QQuickOpenGLShaderEffectMaterialCache : public QObject
public:
static QQuickOpenGLShaderEffectMaterialCache *get(bool create = true) {
QOpenGLContext *ctx = QOpenGLContext::currentContext();
- Q_ASSERT(ctx);
QQuickOpenGLShaderEffectMaterialCache *me = ctx->findChild<QQuickOpenGLShaderEffectMaterialCache *>(QStringLiteral("__qt_ShaderEffectCache"), Qt::FindDirectChildrenOnly);
if (!me && create) {
me = new QQuickOpenGLShaderEffectMaterialCache();
@@ -505,7 +504,7 @@ void QQuickOpenGLShaderEffectNode::markDirtyTexture()
Q_EMIT dirtyTexture();
}
-void QQuickOpenGLShaderEffectNode::textureProviderDestroyed(const QObject *object)
+void QQuickOpenGLShaderEffectNode::textureProviderDestroyed(QObject *object)
{
Q_ASSERT(material());
static_cast<QQuickOpenGLShaderEffectMaterial *>(material())->invalidateTextureProvider(object);
diff --git a/src/quick/items/qquickopenglshadereffectnode_p.h b/src/quick/items/qquickopenglshadereffectnode_p.h
index 6d68ba87b9..705b8d4f47 100644
--- a/src/quick/items/qquickopenglshadereffectnode_p.h
+++ b/src/quick/items/qquickopenglshadereffectnode_p.h
@@ -159,7 +159,7 @@ Q_SIGNALS:
private Q_SLOTS:
void markDirtyTexture();
- void textureProviderDestroyed(const QObject *object);
+ void textureProviderDestroyed(QObject *object);
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index e4480b335a..4e81573356 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -438,7 +438,7 @@ void QQuickPathViewPrivate::updateItem(QQuickItem *item, qreal percent)
att->setOnPath(percent < 1.0);
}
QQuickItemPrivate::get(item)->setCulled(percent >= 1.0);
- QPointF pf = path->pointAt(qMin(percent, qreal(1.0)));
+ QPointF pf = path->pointAtPercent(qMin(percent, qreal(1.0)));
item->setX(pf.x() - item->width()/2);
item->setY(pf.y() - item->height()/2);
}
@@ -1584,12 +1584,12 @@ QPointF QQuickPathViewPrivate::pointNear(const QPointF &point, qreal *nearPercen
qreal res = pathLength / samples;
qreal mindist = 1e10; // big number
- QPointF nearPoint = path->pointAt(0);
+ QPointF nearPoint = path->pointAtPercent(0);
qreal nearPc = 0;
// get rough pos
for (qreal i=1; i < samples; i++) {
- QPointF pt = path->pointAt(i/samples);
+ QPointF pt = path->pointAtPercent(i/samples);
QPointF diff = pt - point;
qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
if (dist < mindist) {
@@ -1602,7 +1602,7 @@ QPointF QQuickPathViewPrivate::pointNear(const QPointF &point, qreal *nearPercen
// now refine
qreal approxPc = nearPc;
for (qreal i = approxPc-1.0; i < approxPc+1.0; i += 1/(2*res)) {
- QPointF pt = path->pointAt(i/samples);
+ QPointF pt = path->pointAtPercent(i/samples);
QPointF diff = pt - point;
qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
if (dist < mindist) {
diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp
index 5e217dcd0c..f3cefc7463 100644
--- a/src/quick/items/qquickrectangle.cpp
+++ b/src/quick/items/qquickrectangle.cpp
@@ -451,8 +451,30 @@ void QQuickRectangle::setGradient(const QJSValue &gradient)
d->gradient = QJSValue();
}
} else if (gradient.isNumber() || gradient.isString()) {
- QGradient preset(gradient.toVariant().value<QGradient::Preset>());
- if (preset.type() != QGradient::NoGradient) {
+ static const QMetaEnum gradientPresetMetaEnum = QMetaEnum::fromType<QGradient::Preset>();
+ Q_ASSERT(gradientPresetMetaEnum.isValid());
+
+ QGradient result;
+
+ // This code could simply use gradient.toVariant().convert<QGradient::Preset>(),
+ // but QTBUG-76377 prevents us from doing error checks. So we need to
+ // do them manually. Also, NumPresets cannot be used.
+
+ if (gradient.isNumber()) {
+ const auto preset = QGradient::Preset(gradient.toInt());
+ if (preset != QGradient::NumPresets && gradientPresetMetaEnum.valueToKey(preset))
+ result = QGradient(preset);
+ } else if (gradient.isString()) {
+ const auto presetName = gradient.toString();
+ if (presetName != QLatin1String("NumPresets")) {
+ bool ok;
+ const auto presetInt = gradientPresetMetaEnum.keyToValue(qPrintable(presetName), &ok);
+ if (ok)
+ result = QGradient(QGradient::Preset(presetInt));
+ }
+ }
+
+ if (result.type() != QGradient::NoGradient) {
d->gradient = gradient;
} else {
qmlWarning(this) << "No such gradient preset '" << gradient.toString() << "'";
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index f6d4e7ed49..83b3372ed9 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -242,7 +242,18 @@ void QQuickRenderControl::initialize(QOpenGLContext *gl)
// It cannot be done here since the surface to use may not be the
// surface belonging to window. In fact window may not have a native
// window/surface at all.
- d->rc->initialize(gl);
+ QSGDefaultRenderContext *rc = qobject_cast<QSGDefaultRenderContext *>(d->rc);
+ if (rc) {
+ QSGDefaultRenderContext::InitParams params;
+ params.sampleCount = qMax(1, gl->format().samples());
+ params.openGLContext = gl;
+ params.initialSurfacePixelSize = d->window->size() * d->window->effectiveDevicePixelRatio();
+ params.maybeSurface = d->window;
+ rc->initialize(&params);
+ } else {
+ // can this happen?
+ d->rc->initialize(nullptr);
+ }
#else
Q_UNUSED(gl)
#endif
diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp
index c8a03aff33..c8c5281089 100644
--- a/src/quick/items/qquickrepeater.cpp
+++ b/src/quick/items/qquickrepeater.cpp
@@ -120,16 +120,17 @@ QQuickRepeaterPrivate::~QQuickRepeaterPrivate()
Also, note that Repeater is \l {Item}-based, and can only repeat \l {Item}-derived objects.
For example, it cannot be used to repeat QtObjects:
- \code
- //bad code
+
+ \qml
+ // bad code:
Item {
- Can't repeat QtObject as it doesn't derive from Item.
+ // Can't repeat QtObject as it doesn't derive from Item.
Repeater {
model: 10
QtObject {}
}
}
- \endcode
+ \endqml
*/
/*!
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index 05d9e5e36d..b3c8386fd9 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -44,6 +44,9 @@
#include <private/qquickopenglshadereffect_p.h>
#endif
#include <private/qquickgenericshadereffect_p.h>
+#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */
+#include <private/qsgrhisupport_p.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -506,13 +509,34 @@ QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
{
setFlag(QQuickItem::ItemHasContents);
+#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */
+ if (QSGRhiSupport::instance()->isRhiEnabled()) {
+ m_impl = new QQuickGenericShaderEffect(this, this);
+ } else
+#endif
+ {
#if QT_CONFIG(opengl)
- if (!qsg_backend_flags().testFlag(QSGContextFactoryInterface::SupportsShaderEffectNode))
- m_glImpl = new QQuickOpenGLShaderEffect(this, this);
+ if (!qsg_backend_flags().testFlag(QSGContextFactoryInterface::SupportsShaderEffectNode))
+ m_glImpl = new QQuickOpenGLShaderEffect(this, this);
- if (!m_glImpl)
+ if (!m_glImpl)
#endif
- m_impl = new QQuickGenericShaderEffect(this, this);
+ m_impl = new QQuickGenericShaderEffect(this, this);
+ }
+}
+
+QQuickShaderEffect::~QQuickShaderEffect()
+{
+ // Delete the implementations now, while they still have have
+ // valid references back to us.
+#if QT_CONFIG(opengl)
+ auto *glImpl = m_glImpl;
+ m_glImpl = nullptr;
+ delete glImpl;
+#endif
+ auto *impl = m_impl;
+ m_impl = nullptr;
+ delete impl;
}
/*!
@@ -865,6 +889,8 @@ QString QQuickShaderEffect::parseLog() // for OpenGL-based autotests
void QQuickShaderEffectPrivate::updatePolish()
{
Q_Q(QQuickShaderEffect);
+ if (!qmlEngine(q))
+ return;
#if QT_CONFIG(opengl)
if (q->m_glImpl) {
q->m_glImpl->maybeUpdateShaders();
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index cabad930fc..c5bddc40d2 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -92,6 +92,7 @@ public:
Q_ENUM(Status)
QQuickShaderEffect(QQuickItem *parent = nullptr);
+ ~QQuickShaderEffect() override;
QByteArray fragmentShader() const;
void setFragmentShader(const QByteArray &code);
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 505940e673..f9f3e5cfa3 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -750,7 +750,7 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
if (!node) {
- node = d->sceneGraphContext()->createInternalImageNode();
+ node = d->sceneGraphContext()->createInternalImageNode(d->sceneGraphRenderContext());
node->setFlag(QSGNode::UsePreprocess);
node->setTexture(m_texture);
QQuickShaderSourceAttachedNode *attached = new QQuickShaderSourceAttachedNode;
diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp
index be297bbe76..8c52703938 100644
--- a/src/quick/items/qquickspriteengine.cpp
+++ b/src/quick/items/qquickspriteengine.cpp
@@ -554,7 +554,7 @@ void QQuickStochasticEngine::restart(int index)
bool randomStart = (m_startTimes.at(index) == NINF);
m_startTimes[index] = m_timeOffset;
if (m_addAdvance)
- m_startTimes[index] += m_advanceTime.elapsed();
+ m_startTimes[index] += m_advanceTimer.elapsed();
if (randomStart)
m_startTimes[index] -= QRandomGenerator::global()->bounded(m_duration.at(index));
int time = m_duration.at(index) + m_startTimes.at(index);
@@ -574,12 +574,12 @@ void QQuickSpriteEngine::restart(int index) //Reimplemented to recognize and han
} else {
m_startTimes[index] = m_timeOffset;
if (m_addAdvance)
- m_startTimes[index] += m_advanceTime.elapsed();
+ m_startTimes[index] += m_advanceTimer.elapsed();
if (randomStart)
m_startTimes[index] -= QRandomGenerator::global()->bounded(m_duration.at(index));
int time = spriteDuration(index) + m_startTimes.at(index);
if (randomStart) {
- int curTime = m_timeOffset + (m_addAdvance ? m_advanceTime.elapsed() : 0);
+ int curTime = m_timeOffset + (m_addAdvance ? m_advanceTimer.elapsed() : 0);
while (time < curTime) //Fast forward through psuedostates as needed
time += spriteDuration(index);
}
@@ -623,10 +623,10 @@ void QQuickSpriteEngine::advance(int idx) //Reimplemented to recognize and handl
}
//just go past the pseudostate logic
} else if (m_startTimes.at(idx) + m_duration.at(idx)
- > int(m_timeOffset + (m_addAdvance ? m_advanceTime.elapsed() : 0))) {
+ > int(m_timeOffset + (m_addAdvance ? m_advanceTimer.elapsed() : 0))) {
//only a pseduostate ended
emit stateChanged(idx);
- addToUpdateList(spriteStart(idx) + spriteDuration(idx) + (m_addAdvance ? m_advanceTime.elapsed() : 0), idx);
+ addToUpdateList(spriteStart(idx) + spriteDuration(idx) + (m_addAdvance ? m_advanceTimer.elapsed() : 0), idx);
return;
}
int nextIdx = nextState(m_things.at(idx), idx);
@@ -685,7 +685,7 @@ uint QQuickStochasticEngine::updateSprites(uint time)//### would returning a lis
}
m_stateUpdates.remove(0, i);
- m_advanceTime.start();
+ m_advanceTimer.start();
m_addAdvance = true;
if (m_stateUpdates.isEmpty())
return uint(-1);
diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h
index d3944b4620..da505be911 100644
--- a/src/quick/items/qquickspriteengine_p.h
+++ b/src/quick/items/qquickspriteengine_p.h
@@ -58,7 +58,7 @@ QT_REQUIRE_CONFIG(quick_sprite);
#include <QObject>
#include <QVector>
#include <QTimer>
-#include <QTime>
+#include <QElapsedTimer>
#include <QList>
#include <QQmlListProperty>
#include <QImage>
@@ -254,7 +254,7 @@ protected:
QVector<int> m_startTimes;
QVector<QPair<uint, QVector<int> > > m_stateUpdates;//### This could be done faster - priority queue?
- QTime m_advanceTime;
+ QElapsedTimer m_advanceTimer;
uint m_timeOffset;
QString m_globalGoal;
int m_maxFrames;
diff --git a/src/quick/items/qquickspritesequence_p.h b/src/quick/items/qquickspritesequence_p.h
index 899ce79e0e..12c80d6a27 100644
--- a/src/quick/items/qquickspritesequence_p.h
+++ b/src/quick/items/qquickspritesequence_p.h
@@ -56,7 +56,6 @@
QT_REQUIRE_CONFIG(quick_sprite);
#include <QtQuick/QQuickItem>
-#include <QTime>
QT_BEGIN_NAMESPACE
diff --git a/src/quick/items/qquickspritesequence_p_p.h b/src/quick/items/qquickspritesequence_p_p.h
index 3579833116..4788cd15aa 100644
--- a/src/quick/items/qquickspritesequence_p_p.h
+++ b/src/quick/items/qquickspritesequence_p_p.h
@@ -57,6 +57,7 @@ QT_REQUIRE_CONFIG(quick_sprite);
#include "qquickitem_p.h"
#include "qquicksprite_p.h"
+#include <QElapsedTimer>
QT_BEGIN_NAMESPACE
@@ -78,7 +79,7 @@ public:
}
QList<QQuickSprite*> m_sprites;
QQuickSpriteEngine* m_spriteEngine;
- QTime m_timestamp;
+ QElapsedTimer m_timestamp;
int m_curFrame;
bool m_pleaseReset;
bool m_running;
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 9583ef4231..75e0a1018f 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -432,6 +432,10 @@ bool QQuickTableViewPrivate::EdgeRange::containsIndex(Qt::Edge edge, int index)
QQuickTableViewPrivate::QQuickTableViewPrivate()
: QQuickFlickablePrivate()
{
+ QObject::connect(&columnWidths, &QQuickTableSectionSizeProvider::sizeChanged,
+ [this] { this->forceLayout();});
+ QObject::connect(&rowHeights, &QQuickTableSectionSizeProvider::sizeChanged,
+ [this] { this->forceLayout();});
}
QQuickTableViewPrivate::~QQuickTableViewPrivate()
@@ -868,6 +872,9 @@ void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
void QQuickTableViewPrivate::forceLayout()
{
+ if (loadedItems.isEmpty())
+ return;
+
clearEdgeSizeCache();
RebuildOptions rebuildOptions = RebuildOption::LayoutOnly;
@@ -1277,6 +1284,10 @@ qreal QQuickTableViewPrivate::getColumnWidth(int column)
if (syncHorizontally)
return syncView->d_func()->getColumnWidth(column);
+ auto cw = columnWidths.size(column);
+ if (cw >= 0)
+ return cw;
+
if (columnWidthProvider.isUndefined())
return noExplicitColumnWidth;
@@ -1314,6 +1325,10 @@ qreal QQuickTableViewPrivate::getRowHeight(int row)
if (syncVertically)
return syncView->d_func()->getRowHeight(row);
+ auto rh = rowHeights.size(row);
+ if (rh >= 0)
+ return rh;
+
if (rowHeightProvider.isUndefined())
return noExplicitRowHeight;
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index caef24293a..5c4ecd60aa 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -113,6 +113,7 @@ QQuickTextControlPrivate::QQuickTextControlPrivate()
wordSelectionEnabled(false),
hasImState(false),
cursorRectangleChanged(false),
+ hoveredMarker(false),
lastSelectionStart(-1),
lastSelectionEnd(-1)
{}
@@ -321,6 +322,9 @@ void QQuickTextControlPrivate::setContent(Qt::TextFormat format, const QString &
formatCursor.select(QTextCursor::Document);
formatCursor.setCharFormat(charFormatForInsertion);
formatCursor.endEditBlock();
+ } else if (format == Qt::MarkdownText) {
+ doc->setBaseUrl(doc->baseUrl().adjusted(QUrl::RemoveFilename));
+ doc->setMarkdown(text);
} else {
#if QT_CONFIG(texthtmlparser)
doc->setHtml(text);
@@ -801,6 +805,12 @@ void QQuickTextControl::setPlainText(const QString &text)
d->setContent(Qt::PlainText, text);
}
+void QQuickTextControl::setMarkdownText(const QString &text)
+{
+ Q_D(QQuickTextControl);
+ d->setContent(Qt::MarkdownText, text);
+}
+
void QQuickTextControl::setHtml(const QString &text)
{
Q_D(QQuickTextControl);
@@ -1027,6 +1037,8 @@ void QQuickTextControlPrivate::mousePressEvent(QMouseEvent *e, const QPointF &po
cursor.clearSelection();
}
}
+ if (interactionFlags & Qt::TextEditable)
+ blockWithMarkerUnderMousePress = q->blockWithMarkerAt(pos);
if (e->button() & Qt::MiddleButton) {
return;
} else if (!(e->button() & Qt::LeftButton)) {
@@ -1198,6 +1210,16 @@ void QQuickTextControlPrivate::mouseReleaseEvent(QMouseEvent *e, const QPointF &
q->updateCursorRectangle(true);
}
+ if ((interactionFlags & Qt::TextEditable) && (e->button() & Qt::LeftButton) && blockWithMarkerUnderMousePress.isValid()) {
+ QTextBlock block = q->blockWithMarkerAt(pos);
+ if (block == blockWithMarkerUnderMousePress) {
+ auto fmt = block.blockFormat();
+ fmt.setMarker(fmt.marker() == QTextBlockFormat::Unchecked ?
+ QTextBlockFormat::Checked : QTextBlockFormat::Unchecked);
+ cursor.setBlockFormat(fmt);
+ }
+ }
+
if (interactionFlags & Qt::LinksAccessibleByMouse) {
if (!(e->button() & Qt::LeftButton))
return;
@@ -1403,7 +1425,7 @@ QVariant QQuickTextControl::inputMethodQuery(Qt::InputMethodQuery property, QVar
case Qt::ImAnchorPosition:
return QVariant(d->cursor.anchor() - block.position());
case Qt::ImAbsolutePosition:
- return QVariant(d->cursor.anchor());
+ return QVariant(d->cursor.position());
case Qt::ImTextAfterCursor:
{
int maxLength = argument.isValid() ? argument.toInt() : 1024;
@@ -1480,8 +1502,15 @@ void QQuickTextControlPrivate::hoverEvent(QHoverEvent *e, const QPointF &pos)
if (hoveredLink != link) {
hoveredLink = link;
emit q->linkHovered(link);
+ qCDebug(DBG_HOVER_TRACE) << q << e->type() << pos << "hoveredLink" << hoveredLink;
+ } else {
+ QTextBlock block = q->blockWithMarkerAt(pos);
+ if (block.isValid() != hoveredMarker)
+ emit q->markerHovered(block.isValid());
+ hoveredMarker = block.isValid();
+ if (hoveredMarker)
+ qCDebug(DBG_HOVER_TRACE) << q << e->type() << pos << "hovered marker" << block.blockFormat().marker() << block.text();
}
- qCDebug(DBG_HOVER_TRACE) << q << e->type() << pos << "hoveredLink" << hoveredLink;
}
bool QQuickTextControl::hasImState() const
@@ -1557,6 +1586,12 @@ QString QQuickTextControl::anchorAt(const QPointF &pos) const
return d->doc->documentLayout()->anchorAt(pos);
}
+QTextBlock QQuickTextControl::blockWithMarkerAt(const QPointF &pos) const
+{
+ Q_D(const QQuickTextControl);
+ return d->doc->documentLayout()->blockWithMarkerAt(pos);
+}
+
void QQuickTextControl::setAcceptRichText(bool accept)
{
Q_D(QQuickTextControl);
@@ -1786,6 +1821,13 @@ QString QQuickTextControl::toHtml() const
}
#endif
+#if QT_CONFIG(textmarkdownwriter)
+QString QQuickTextControl::toMarkdown() const
+{
+ return document()->toMarkdown();
+}
+#endif
+
bool QQuickTextControl::cursorOn() const
{
Q_D(const QQuickTextControl);
diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h
index c99736a874..3c7d48f918 100644
--- a/src/quick/items/qquicktextcontrol_p.h
+++ b/src/quick/items/qquicktextcontrol_p.h
@@ -93,6 +93,9 @@ public:
#if QT_CONFIG(texthtmlparser)
QString toHtml() const;
#endif
+#if QT_CONFIG(textmarkdownwriter)
+ QString toMarkdown() const;
+#endif
bool hasImState() const;
bool overwriteMode() const;
@@ -107,6 +110,7 @@ public:
QString hoveredLink() const;
QString anchorAt(const QPointF &pos) const;
+ QTextBlock blockWithMarkerAt(const QPointF &pos) const;
void setCursorWidth(int width);
@@ -128,6 +132,7 @@ public:
public Q_SLOTS:
void setPlainText(const QString &text);
+ void setMarkdownText(const QString &text);
void setHtml(const QString &text);
#if QT_CONFIG(clipboard)
@@ -160,6 +165,8 @@ Q_SIGNALS:
void cursorRectangleChanged();
void linkActivated(const QString &link);
void linkHovered(const QString &link);
+ void markerClicked();
+ void markerHovered(bool marker);
public:
virtual void processEvent(QEvent *e, const QMatrix &matrix);
diff --git a/src/quick/items/qquicktextcontrol_p_p.h b/src/quick/items/qquicktextcontrol_p_p.h
index 0582e6d113..5648c31e21 100644
--- a/src/quick/items/qquicktextcontrol_p_p.h
+++ b/src/quick/items/qquicktextcontrol_p_p.h
@@ -54,6 +54,7 @@
#include "QtGui/qtextdocumentfragment.h"
#include "QtGui/qtextcursor.h"
#include "QtGui/qtextformat.h"
+#include "QtGui/qtextobject.h"
#include "QtGui/qabstracttextdocumentlayout.h"
#include "QtCore/qbasictimer.h"
#include "QtCore/qpointer.h"
@@ -139,6 +140,7 @@ public:
QString anchorOnMousePress;
QString linkToCopy;
QString hoveredLink;
+ QTextBlock blockWithMarkerUnderMousePress;
QBasicTimer cursorBlinkTimer;
QBasicTimer tripleClickTimer;
@@ -163,6 +165,7 @@ public:
bool wordSelectionEnabled : 1;
bool hasImState : 1;
bool cursorRectangleChanged : 1;
+ bool hoveredMarker: 1;
int lastSelectionStart;
int lastSelectionEnd;
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index b299e7c92f..7414d7fd6a 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -194,6 +194,11 @@ QString QQuickTextEdit::text() const
d->text = d->control->toHtml();
else
#endif
+#if QT_CONFIG(textmarkdownwriter)
+ if (d->markdownText)
+ d->text = d->control->toMarkdown();
+ else
+#endif
d->text = d->control->toPlainText();
d->textCached = true;
}
@@ -407,6 +412,7 @@ void QQuickTextEdit::setText(const QString &text)
d->document->clearResources();
d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
+ d->markdownText = d->format == MarkdownText;
if (!isComponentComplete()) {
d->text = text;
} else if (d->richText) {
@@ -415,6 +421,8 @@ void QQuickTextEdit::setText(const QString &text)
#else
d->control->setPlainText(text);
#endif
+ } else if (d->markdownText) {
+ d->control->setMarkdownText(text);
} else {
d->control->setPlainText(text);
}
@@ -486,6 +494,7 @@ void QQuickTextEdit::setTextFormat(TextFormat format)
bool wasRich = d->richText;
d->richText = format == RichText || (format == AutoText && (wasRich || Qt::mightBeRichText(text())));
+ d->markdownText = format == MarkdownText;
#if QT_CONFIG(texthtmlparser)
if (isComponentComplete()) {
@@ -1463,8 +1472,12 @@ void QQuickTextEdit::componentComplete()
d->control->setHtml(d->text);
else
#endif
- if (!d->text.isEmpty())
- d->control->setPlainText(d->text);
+ if (!d->text.isEmpty()) {
+ if (d->markdownText)
+ d->control->setMarkdownText(d->text);
+ else
+ d->control->setPlainText(d->text);
+ }
if (d->dirty) {
d->determineHorizontalAlignment();
@@ -2310,6 +2323,7 @@ void QQuickTextEditPrivate::init()
QObject::connect(document, &QQuickTextDocumentWithImageResources::contentsChange, q, &QQuickTextEdit::q_contentsChange);
QObject::connect(document->documentLayout(), &QAbstractTextDocumentLayout::updateBlock, q, &QQuickTextEdit::invalidateBlock);
QObject::connect(control, &QQuickTextControl::linkHovered, q, &QQuickTextEdit::q_linkHovered);
+ QObject::connect(control, &QQuickTextControl::markerHovered, q, &QQuickTextEdit::q_markerHovered);
document->setDefaultFont(font);
document->setDocumentMargin(textMargin);
@@ -2601,6 +2615,19 @@ void QQuickTextEdit::q_linkHovered(const QString &link)
#endif
}
+void QQuickTextEdit::q_markerHovered(bool hovered)
+{
+ Q_D(QQuickTextEdit);
+#if QT_CONFIG(cursor)
+ if (!hovered) {
+ setCursor(d->cursorToRestoreAfterHover);
+ } else if (cursor().shape() != Qt::PointingHandCursor) {
+ d->cursorToRestoreAfterHover = cursor().shape();
+ setCursor(Qt::PointingHandCursor);
+ }
+#endif
+}
+
void QQuickTextEdit::q_updateAlignment()
{
Q_D(QQuickTextEdit);
diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h
index 259a614d6b..2d1b6c7f9c 100644
--- a/src/quick/items/qquicktextedit_p.h
+++ b/src/quick/items/qquicktextedit_p.h
@@ -134,7 +134,8 @@ public:
enum TextFormat {
PlainText = Qt::PlainText,
RichText = Qt::RichText,
- AutoText = Qt::AutoText
+ AutoText = Qt::AutoText,
+ MarkdownText = Qt::MarkdownText
};
Q_ENUM(TextFormat)
@@ -375,6 +376,7 @@ private Q_SLOTS:
void invalidateBlock(const QTextBlock &block);
void updateCursor();
void q_linkHovered(const QString &link);
+ void q_markerHovered(bool hovered);
void q_updateAlignment();
void updateSize();
void triggerPreprocess();
diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h
index 389ce3175c..be555d44fd 100644
--- a/src/quick/items/qquicktextedit_p_p.h
+++ b/src/quick/items/qquicktextedit_p_p.h
@@ -127,7 +127,7 @@ public:
, focusOnPress(true), persistentSelection(false), requireImplicitWidth(false)
, selectByMouse(false), canPaste(false), canPasteValid(false), hAlignImplicit(true)
, textCached(true), inLayout(false), selectByKeyboard(false), selectByKeyboardSet(false)
- , hadSelection(false)
+ , hadSelection(false), markdownText(false)
{
}
@@ -225,6 +225,7 @@ public:
bool selectByKeyboard:1;
bool selectByKeyboardSet:1;
bool hadSelection : 1;
+ bool markdownText : 1;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index 5f6fd8f50f..598ebb7a68 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -1009,9 +1009,10 @@ void QQuickTextInput::setAutoScroll(bool b)
an acceptable or intermediate state. The accepted signal will only be sent
if the text is in an acceptable state when enter is pressed.
- Currently supported validators are IntValidator, DoubleValidator and
- RegExpValidator. An example of using validators is shown below, which allows
- input of integers between 11 and 31 into the text input:
+ Currently supported validators are IntValidator, DoubleValidator,
+ RegExpValidator and RegularExpressionValidator. An example of using
+ validators is shown below, which allows input of integers between 11 and 31
+ into the text input:
\code
import QtQuick 2.0
diff --git a/src/quick/items/qquicktextnode.cpp b/src/quick/items/qquicktextnode.cpp
index 0dd12207b7..9110a0664f 100644
--- a/src/quick/items/qquicktextnode.cpp
+++ b/src/quick/items/qquicktextnode.cpp
@@ -160,7 +160,7 @@ void QQuickTextNode::addRectangleNode(const QRectF &rect, const QColor &color)
void QQuickTextNode::addImage(const QRectF &rect, const QImage &image)
{
QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext();
- QSGInternalImageNode *node = sg->sceneGraphContext()->createInternalImageNode();
+ QSGInternalImageNode *node = sg->sceneGraphContext()->createInternalImageNode(sg);
QSGTexture *texture = sg->createTexture(image);
if (m_ownerElement->smooth())
texture->setFiltering(QSGTexture::Linear);
diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp
index c411da9519..fa9b44aa22 100644
--- a/src/quick/items/qquickview.cpp
+++ b/src/quick/items/qquickview.cpp
@@ -44,8 +44,6 @@
#include "qquickitem_p.h"
#include "qquickitemchangelistener_p.h"
-#include <private/qqmlmemoryprofiler_p.h>
-
#include <QtQml/qqmlengine.h>
#include <private/qqmlengine_p.h>
#include <private/qv4qobjectwrapper_p.h>
@@ -101,7 +99,6 @@ void QQuickViewPrivate::execute()
component = nullptr;
}
if (!source.isEmpty()) {
- QML_MEMORY_SCOPE_URL(engine.data()->baseUrl().resolved(source));
component = new QQmlComponent(engine.data(), source, q);
if (!component->isLoading()) {
q->continueExecute();
@@ -504,14 +501,14 @@ void QQuickViewPrivate::setRootObject(QObject *obj)
sgItem->setParentItem(q->QQuickWindow::contentItem());
QQml_setParent_noEvent(sgItem, q->QQuickWindow::contentItem());
} else if (qobject_cast<QWindow *>(obj)) {
- qWarning() << "QQuickView does not support using windows as a root item." << endl
- << endl
- << "If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << endl;
+ qWarning() << "QQuickView does not support using windows as a root item." << Qt::endl
+ << Qt::endl
+ << "If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << Qt::endl;
} else {
- qWarning() << "QQuickView only supports loading of root objects that derive from QQuickItem." << endl
- << endl
- << "Ensure your QML code is written for QtQuick 2, and uses a root that is or" << endl
- << "inherits from QtQuick's Item (not a Timer, QtObject, etc)." << endl;
+ qWarning() << "QQuickView only supports loading of root objects that derive from QQuickItem." << Qt::endl
+ << Qt::endl
+ << "Ensure your QML code is written for QtQuick 2, and uses a root that is or" << Qt::endl
+ << "inherits from QtQuick's Item (not a Timer, QtObject, etc)." << Qt::endl;
delete obj;
root = nullptr;
}
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 24a17ce80f..30738b3db6 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -52,8 +52,9 @@
#include <private/qquickpointerhandler_p.h>
#include <QtQuick/private/qsgrenderer_p.h>
-#include <QtQuick/private/qsgtexture_p.h>
+#include <QtQuick/private/qsgplaintexture_p.h>
#include <private/qsgrenderloop_p.h>
+#include <private/qsgrhisupport_p.h>
#include <private/qquickrendercontrol_p.h>
#include <private/qquickanimatorcontroller_p.h>
#include <private/qquickprofiler_p.h>
@@ -75,7 +76,6 @@
#include <QtQuick/private/qquickpixmapcache_p.h>
-#include <private/qqmlmemoryprofiler_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
#include <private/qqmldebugconnector_p.h>
#if QT_CONFIG(opengl)
@@ -86,6 +86,8 @@
#include <private/qdebug_p.h>
#endif
+#include <QtGui/private/qrhi_p.h>
+
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch")
@@ -420,7 +422,6 @@ void forceUpdate(QQuickItem *item)
void QQuickWindowPrivate::syncSceneGraph()
{
- QML_MEMORY_SCOPE_STRING("SceneGraph");
Q_Q(QQuickWindow);
animationController->beforeNodeSync();
@@ -453,13 +454,40 @@ void QQuickWindowPrivate::syncSceneGraph()
runAndClearJobs(&afterSynchronizingJobs);
}
-void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
+void QQuickWindowPrivate::emitBeforeRenderPassRecording(void *ud)
+{
+ QQuickWindow *w = reinterpret_cast<QQuickWindow *>(ud);
+ emit w->beforeRenderPassRecording();
+}
+
+void QQuickWindowPrivate::emitAfterRenderPassRecording(void *ud)
+{
+ QQuickWindow *w = reinterpret_cast<QQuickWindow *>(ud);
+ emit w->afterRenderPassRecording();
+}
+
+void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfaceSize)
{
- QML_MEMORY_SCOPE_STRING("SceneGraph");
Q_Q(QQuickWindow);
if (!renderer)
return;
+ if (rhi) {
+ // ### no offscreen ("renderTargetId") support yet
+ context->beginNextRhiFrame(renderer,
+ swapchain->currentFrameRenderTarget(),
+ rpDescForSwapchain,
+ swapchain->currentFrameCommandBuffer(),
+ emitBeforeRenderPassRecording,
+ emitAfterRenderPassRecording,
+ q);
+ } else {
+ context->beginNextFrame(renderer,
+ emitBeforeRenderPassRecording,
+ emitAfterRenderPassRecording,
+ q);
+ }
+
animationController->advance();
emit q->beforeRendering();
runAndClearJobs(&beforeRenderingJobs);
@@ -472,24 +500,42 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
renderer->setDeviceRect(rect);
renderer->setViewportRect(rect);
if (QQuickRenderControl::renderWindowFor(q)) {
- renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), size));
+ renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), size), false);
renderer->setDevicePixelRatio(devicePixelRatio);
} else {
- renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), rect.size()));
+ renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), rect.size()), false);
renderer->setDevicePixelRatio(1);
}
} else {
- QRect rect(QPoint(0, 0), devicePixelRatio * size);
+ QSize pixelSize;
+ QSizeF logicalSize;
+ if (surfaceSize.isEmpty()) {
+ pixelSize = size * devicePixelRatio;
+ logicalSize = size;
+ } else {
+ pixelSize = surfaceSize;
+ logicalSize = QSizeF(surfaceSize) / devicePixelRatio;
+ }
+ QRect rect(QPoint(0, 0), pixelSize);
renderer->setDeviceRect(rect);
renderer->setViewportRect(rect);
- renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), size));
+ const bool flipY = rhi ? !rhi->isYUpInNDC() : false;
+ renderer->setProjectionMatrixToRect(QRectF(QPoint(0, 0), logicalSize), flipY);
renderer->setDevicePixelRatio(devicePixelRatio);
}
- context->renderNextFrame(renderer, fboId);
+ if (rhi)
+ context->renderNextRhiFrame(renderer);
+ else
+ context->renderNextFrame(renderer, fboId);
}
emit q->afterRendering();
runAndClearJobs(&afterRenderingJobs);
+
+ if (rhi)
+ context->endNextRhiFrame(renderer);
+ else
+ context->endNextFrame(renderer);
}
QQuickWindowPrivate::QQuickWindowPrivate()
@@ -525,6 +571,9 @@ QQuickWindowPrivate::QQuickWindowPrivate()
, renderTargetId(0)
, vaoHelper(nullptr)
, incubationController(nullptr)
+ , hasActiveSwapchain(false)
+ , hasRenderableSwapchain(false)
+ , swapchainJustBecameRenderable(false)
{
#if QT_CONFIG(quick_draganddrop)
dragGrabber = new QQuickDragGrabber;
@@ -542,6 +591,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
{
q_ptr = c;
+
Q_Q(QQuickWindow);
contentItem = new QQuickRootItem;
@@ -579,6 +629,10 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
q->setSurfaceType(windowManager ? windowManager->windowSurfaceType() : QSurface::OpenGLSurface);
q->setFormat(sg->defaultSurfaceFormat());
+#if QT_CONFIG(vulkan)
+ if (q->surfaceType() == QSurface::VulkanSurface)
+ q->setVulkanInstance(QSGRhiSupport::vulkanInstance());
+#endif
animationController = new QQuickAnimatorController(q);
@@ -699,7 +753,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
if (!item->contains(pos))
break;
- qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << hex << p.id() << "->" << item;
+ qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << Qt::hex << p.id() << "->" << item;
QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event.data(), item, false));
// Send a single press and see if that's accepted
@@ -741,7 +795,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
QCoreApplication::sendEvent(item, me.data());
event->setAccepted(me->isAccepted());
if (me->isAccepted()) {
- qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << hex << p.id() << "->" << mouseGrabberItem;
+ qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << Qt::hex << p.id() << "->" << mouseGrabberItem;
}
return event->isAccepted();
} else {
@@ -1580,6 +1634,7 @@ bool QQuickWindowPrivate::clearHover(ulong timestamp)
bool accepted = false;
for (QQuickItem* item : qAsConst(hoverItems)) {
accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), timestamp, true) || accepted;
+#if QT_CONFIG(cursor)
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
if (itemPrivate->hasPointerHandlers()) {
pos = q->mapFromGlobal(QCursor::pos());
@@ -1591,6 +1646,7 @@ bool QQuickWindowPrivate::clearHover(ulong timestamp)
if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h))
hh->handlePointerEvent(pointerEvent);
}
+#endif
}
hoverItems.clear();
return accepted;
@@ -1629,7 +1685,9 @@ bool QQuickWindow::event(QEvent *e)
QGuiApplication::keyboardModifiers(), 0L, accepted);
d->lastMousePosition = enter->windowPos();
enter->setAccepted(accepted);
+#if QT_CONFIG(cursor)
d->updateCursor(mapFromGlobal(QCursor::pos()));
+#endif
return delivered;
}
break;
@@ -2468,7 +2526,7 @@ void QQuickWindowPrivate::deliverTouchEvent(QQuickPointerTouchEvent *event)
QQuickEventPoint *point = event->point(i);
if (point->state() == QQuickEventPoint::Released) {
int id = point->pointId();
- qCDebug(DBG_TOUCH_TARGET) << "TP" << hex << id << "released";
+ qCDebug(DBG_TOUCH_TARGET) << "TP" << Qt::hex << id << "released";
point->setGrabberItem(nullptr);
if (id == touchMouseId)
cancelTouchMouseSynthesis();
@@ -2565,7 +2623,7 @@ bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event,
if (point->grabberPointerHandler())
cancelTouchMouseSynthesis();
} else {
- qCWarning(DBG_TOUCH_TARGET) << "during delivery of touch press, synth-mouse ID" << hex << touchMouseId << "is missing from" << event;
+ qCWarning(DBG_TOUCH_TARGET) << "during delivery of touch press, synth-mouse ID" << Qt::hex << touchMouseId << "is missing from" << event;
}
}
for (int i = 0; i < pointCount; ++i) {
@@ -2707,7 +2765,7 @@ void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo
if (point.state() == Qt::TouchPointPressed) {
if (auto *tp = ptEvent->pointById(point.id())) {
if (tp->exclusiveGrabber() == item) {
- qCDebug(DBG_TOUCH_TARGET) << "TP" << hex << point.id() << "disassociated";
+ qCDebug(DBG_TOUCH_TARGET) << "TP" << Qt::hex << point.id() << "disassociated";
tp->setGrabberItem(nullptr);
}
}
@@ -2986,7 +3044,7 @@ bool QQuickWindowPrivate::sendFilteredPointerEventImpl(QQuickPointerEvent *event
qCDebug(DBG_TOUCH) << "touch event intercepted as synth mouse event by childMouseEventFilter of " << filteringParent;
skipDelivery.append(filteringParent);
if (t != QEvent::MouseButtonRelease) {
- qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << hex << tp.id() << "->" << filteringParent;
+ qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << Qt::hex << tp.id() << "->" << filteringParent;
pointerEventInstance(dev)->pointById(tp.id())->setGrabberItem(filteringParent);
touchMouseUnset = false; // We want to leave touchMouseId and touchMouseDevice set
if (mouseEvent->isAccepted())
@@ -3627,24 +3685,20 @@ void QQuickWindow::setTransientParent_helper(QQuickWindow *window)
/*!
Returns the OpenGL context used for rendering.
- If the scene graph is not ready, or the scene graph is not using OpenGL,
- this function will return null.
-
- \note If using a scene graph adaptation other than OpenGL this
- function will return nullptr.
+ \note If the scene graph is not ready, or the scene graph is not using
+ OpenGL (or RHI over OpenGL), this function will return null.
\sa sceneGraphInitialized(), sceneGraphInvalidated()
*/
-
QOpenGLContext *QQuickWindow::openglContext() const
{
#if QT_CONFIG(opengl)
Q_D(const QQuickWindow);
if (d->context && d->context->isValid()) {
QSGRendererInterface *rif = d->context->sceneGraphContext()->rendererInterface(d->context);
- if (rif && rif->graphicsApi() == QSGRendererInterface::OpenGL) {
- auto openglRenderContext = static_cast<const QSGDefaultRenderContext *>(d->context);
- return openglRenderContext->openglContext();
+ if (rif) {
+ return reinterpret_cast<QOpenGLContext *>(rif->getResource(const_cast<QQuickWindow *>(this),
+ QSGRendererInterface::OpenGLContextResource));
}
}
#endif
@@ -3777,6 +3831,8 @@ bool QQuickWindow::isSceneGraphInitialized() const
This function only has an effect when using the default OpenGL scene
graph adaptation.
+ \note This function has no effect when running on the RHI graphics abstraction.
+
\warning
This function can only be called from the thread doing
the rendering.
@@ -3785,6 +3841,9 @@ bool QQuickWindow::isSceneGraphInitialized() const
void QQuickWindow::setRenderTarget(QOpenGLFramebufferObject *fbo)
{
Q_D(QQuickWindow);
+ if (d->rhi)
+ return;
+
if (d->context && QThread::currentThread() != d->context->thread()) {
qWarning("QQuickWindow::setRenderTarget: Cannot set render target from outside the rendering thread");
return;
@@ -3866,9 +3925,11 @@ QSize QQuickWindow::renderTargetSize() const
The default is to render to the surface of the window, in which
case the render target is 0.
- \note
- This function will return nullptr when not using the OpenGL scene
+ \note This function will return nullptr when not using the OpenGL scene
graph adaptation.
+
+ \note This function has no effect and returns nullptr when running on the
+ RHI graphics abstraction.
*/
QOpenGLFramebufferObject *QQuickWindow::renderTarget() const
{
@@ -3894,12 +3955,23 @@ QImage QQuickWindow::grabWindow()
Q_D(QQuickWindow);
if (!isVisible() && !d->renderControl) {
+ // backends like software and d3d12 can grab regardless of the window state
if (d->windowManager && (d->windowManager->flags() & QSGRenderLoop::SupportsGrabWithoutExpose))
return d->windowManager->grab(this);
}
-#if QT_CONFIG(opengl)
if (!isVisible() && !d->renderControl) {
+ if (d->rhi) {
+ // ### we may need a full offscreen round when non-exposed...
+
+ if (d->renderControl)
+ return d->renderControl->grab();
+ else if (d->windowManager)
+ return d->windowManager->grab(this);
+ return QImage();
+ }
+
+#if QT_CONFIG(opengl)
auto openglRenderContext = static_cast<QSGDefaultRenderContext *>(d->context);
if (!openglRenderContext->openglContext()) {
if (!handle() || !size().isValid()) {
@@ -3912,7 +3984,9 @@ QImage QQuickWindow::grabWindow()
context.setShareContext(qt_gl_global_share_context());
context.create();
context.makeCurrent(this);
- d->context->initialize(&context);
+ QSGDefaultRenderContext::InitParams rcParams;
+ rcParams.openGLContext = &context;
+ d->context->initialize(&rcParams);
d->polishItems();
d->syncSceneGraph();
@@ -3927,8 +4001,9 @@ QImage QQuickWindow::grabWindow()
return image;
}
- }
#endif
+ }
+
if (d->renderControl)
return d->renderControl->grab();
else if (d->windowManager)
@@ -4066,6 +4141,17 @@ QQmlIncubationController *QQuickWindow::incubationController() const
The OpenGL context used for rendering the scene graph will be bound
at this point.
+ When using the RHI and a graphics API other than OpenGL, the signal is
+ emitted after the preparations for the frame have been done, meaning there
+ is a command buffer in recording mode, where applicable. If desired, the
+ slot function connected to this signal can query native resources like the
+ command before via QSGRendererInterface. Note however that the recording of
+ the main render pass is not yet started at this point and it is not
+ possible to add commands within that pass. Instead, use
+ beforeRenderPassRecording() for that. However, connecting to this signal is
+ still important if the recording of copy type of commands is desired since
+ those cannot be enqueued within a render pass.
+
\warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that
the connection is direct (see Qt::ConnectionType).
@@ -4087,6 +4173,15 @@ QQmlIncubationController *QQuickWindow::incubationController() const
The OpenGL context used for rendering the scene graph will be bound at this point.
+ When using the RHI and a graphics API other than OpenGL, the signal is
+ emitted after scene graph has added its commands to the command buffer,
+ which is not yet submitted to the graphics queue. If desired, the slot
+ function connected to this signal can query native resources, like the
+ command buffer, before via QSGRendererInterface. Note however that the
+ render pass (or passes) are already recorded at this point and it is not
+ possible to add more commands within the scenegraph's pass. Instead, use
+ afterRenderPassRecording() for that.
+
\warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that
the connection is direct (see Qt::ConnectionType).
@@ -4099,14 +4194,78 @@ QQmlIncubationController *QQuickWindow::incubationController() const
*/
/*!
+ \fn void QQuickWindow::beforeRenderPassRecording()
+
+ This signal is emitted before the scenegraph starts recording commands for
+ the main render pass. (Layers have their own passes and are fully recorded
+ by the time this signal is emitted.) The render pass is already active on
+ the command buffer when the signal is emitted.
+
+ This signal is applicable when using the RHI graphics abstraction with the
+ scenegraph. It is emitted later than beforeRendering() and it guarantees
+ that not just the frame, but also the recording of the scenegraph's main
+ render pass is active. This allows inserting commands without having to
+ generate an entire, separate render pass (which would typically clear the
+ attached images). The native graphics objects can be queried via
+ QSGRendererInterface.
+
+ When not running with the RHI (and using OpenGL directly), the signal is
+ emitted after the renderer has cleared the render target. This makes it
+ possible to create appliations that function identically both with and
+ without the RHI.
+
+ \note Resource updates (uploads, copies) typically cannot be enqueued from
+ within a render pass. Therefore, more complex user rendering will need to
+ connect to both the beforeRendering() and this signals.
+
+ \warning This signal is emitted from the scene graph rendering thread. If your
+ slot function needs to finish before execution continues, you must make sure that
+ the connection is direct (see Qt::ConnectionType).
+
+ \since 5.14
+*/
+
+/*!
+ \fn void QQuickWindow::afterRenderPassRecording()
+
+ This signal is emitted after the scenegraph has recorded the commands for
+ its main render pass, but the pass is not yet finalized on the command
+ buffer.
+
+ This signal is applicable when using the RHI graphics abstraction with the
+ scenegraph. It is emitted earlier than afterRendering() and it guarantees
+ that not just the frame, but also the recording of the scenegraph's main
+ render pass is still active. This allows inserting commands without having
+ to generate an entire, separate render pass (which would typically clear
+ the attached images). The native graphics objects can be queried via
+ QSGRendererInterface.
+
+ When not running with the RHI (and using OpenGL directly), the signal is
+ emitted after the renderer has finished its rendering, but before
+ afterRendering(). This makes it possible to create appliations that
+ function identically both with and without the RHI.
+
+ \note Resource updates (uploads, copies) typically cannot be enqueued from
+ within a render pass. Therefore, more complex user rendering will need to
+ connect to both the beforeRendering() and this signals.
+
+ \warning This signal is emitted from the scene graph rendering thread. If your
+ slot function needs to finish before execution continues, you must make sure that
+ the connection is direct (see Qt::ConnectionType).
+
+ \since 5.14
+*/
+
+/*!
\fn void QQuickWindow::afterAnimating()
This signal is emitted on the gui thread before requesting the render thread to
perform the synchronization of the scene graph.
- Unlike the other similar signals, this one is emitted on the gui thread instead
- of the render thread. It can be used to synchronize external animation systems
- with the QML content.
+ Unlike the other similar signals, this one is emitted on the gui thread
+ instead of the render thread. It can be used to synchronize external
+ animation systems with the QML content. At the same time this means that
+ this signal is not suitable for triggering graphics operations.
\since 5.3
*/
@@ -4166,7 +4325,15 @@ QQmlIncubationController *QQuickWindow::incubationController() const
The color buffer is cleared by default.
- \sa beforeRendering()
+ \warning This flag is ignored completely when running with the RHI graphics
+ abstraction instead of using OpenGL directly. As explicit clear commands
+ simply do not exist in some modern APIs, the scene graph cannot offer this
+ flexibility anymore. The images associated with a render target will always
+ get cleared when a render pass starts. As a solution, an alternative to
+ disabling scene graph issued clears is provided in form of the
+ beforeRenderPassRecording() signal.
+
+ \sa beforeRendering(), beforeRenderPassRecording()
*/
void QQuickWindow::setClearBeforeRendering(bool enabled)
@@ -4270,12 +4437,15 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateText
\note This function only has an effect when using the default OpenGL scene graph
adaptation.
+ \note This function has no effect when running on the RHI graphics abstraction.
+
\sa sceneGraphInitialized(), QSGTexture
*/
QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
{
#if QT_CONFIG(opengl)
- if (openglContext()) {
+ Q_D(const QQuickWindow);
+ if (!d->rhi && openglContext()) {
QSGPlainTexture *texture = new QSGPlainTexture();
texture->setTextureId(id);
texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
@@ -4378,15 +4548,19 @@ void QQuickWindow::setDefaultAlphaBuffer(bool useAlpha)
\note This function only has an effect when using the default OpenGL scene graph
adaptation.
- \sa QQuickWindow::beforeRendering()
+ \note This function has no effect when running on the RHI graphics
+ abstraction. With the RHI, the functions to call when enqueuing native
+ graphics commands are beginExternalCommands() and endExternalCommands().
+
+ \sa QQuickWindow::beforeRendering(), beginExternalCommands(), endExternalCommands()
*/
void QQuickWindow::resetOpenGLState()
{
- if (!openglContext())
- return;
-
Q_D(QQuickWindow);
+ if (d->rhi || !openglContext())
+ return;
+
QOpenGLContext *ctx = openglContext();
QOpenGLFunctions *gl = ctx->functions();
@@ -4433,6 +4607,111 @@ void QQuickWindow::resetOpenGLState()
QOpenGLFramebufferObject::bindDefault();
}
#endif
+
+/*!
+ \struct QQuickWindow::GraphicsStateInfo
+ \inmodule QtQuick
+ \since 5.14
+
+ \brief Describes some of the RHI's graphics state at the point of a
+ \l{QQuickWindow::beginExternalCommands()}{beginExternalCommands()} call.
+ */
+
+/*!
+ \return a pointer to a GraphicsStateInfo struct describing some of the
+ RHI's internal state, in particular, the double or tripple buffering status
+ of the backend (such as, the Vulkan or Metal integrations). This is
+ relevant when the underlying graphics APIs is Vulkan or Metal, and the
+ external rendering code wishes to perform double or tripple buffering of
+ its own often-changing resources, such as, uniform buffers, in order to
+ avoid stalling the pipeline.
+ */
+const QQuickWindow::GraphicsStateInfo *QQuickWindow::graphicsStateInfo()
+{
+ Q_D(QQuickWindow);
+ if (d->rhi) {
+ d->rhiStateInfo.currentFrameSlot = d->rhi->currentFrameSlot();
+ d->rhiStateInfo.framesInFlight = d->rhi->resourceLimit(QRhi::FramesInFlight);
+ }
+ return &d->rhiStateInfo;
+}
+
+/*!
+ When mixing raw graphics (OpenGL, Vulkan, Metal, etc.) commands with scene
+ graph rendering, it is necessary to call this function before recording
+ commands to the command buffer used by the scene graph to render its main
+ render pass. This is to avoid clobbering state.
+
+ In practice this function is often called from a slot connected to the
+ beforeRenderPassRecording() or afterRenderPassRecording() signals.
+
+ The function does not need to be called when recording commands to the
+ application's own command buffer (such as, a VkCommandBuffer or
+ MTLCommandBuffer + MTLRenderCommandEncoder created and managed by the
+ application, not retrieved from the scene graph). With graphics APIs where
+ no native command buffer concept is exposed (OpenGL, Direct 3D 11),
+ beginExternalCommands() and endExternalCommands() together provide a
+ replacement for resetOpenGLState().
+
+ \note This function has no effect when the scene graph is using OpenGL
+ directly and the RHI graphics abstraction layer is not in use. Refer to
+ resetOpenGLState() in that case.
+
+ \sa endExternalCommands()
+
+ \since 5.14
+ */
+void QQuickWindow::beginExternalCommands()
+{
+#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */
+ Q_D(QQuickWindow);
+ if (d->rhi && d->context && d->context->isValid()) {
+ QSGDefaultRenderContext *rc = static_cast<QSGDefaultRenderContext *>(d->context);
+ QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer();
+ if (cb)
+ cb->beginExternal();
+ }
+#endif
+}
+
+/*!
+ When mixing raw graphics (OpenGL, Vulkan, Metal, etc.) commands with scene
+ graph rendering, it is necessary to call this function after recording
+ commands to the command buffer used by the scene graph to render its main
+ render pass. This is to avoid clobbering state.
+
+ In practice this function is often called from a slot connected to the
+ beforeRenderPassRecording() or afterRenderPassRecording() signals.
+
+ The function does not need to be called when recording commands to the
+ application's own command buffer (such as, a VkCommandBuffer or
+ MTLCommandBuffer + MTLRenderCommandEncoder created and managed by the
+ application, not retrieved from the scene graph). With graphics APIs where
+ no native command buffer concept is exposed (OpenGL, Direct 3D 11),
+ beginExternalCommands() and endExternalCommands() together provide a
+ replacement for resetOpenGLState().
+
+ \note This function has no effect when the scene graph is using OpenGL
+ directly and the RHI graphics abstraction layer is not in use. Refer to
+ resetOpenGLState() in that case.
+
+ \sa beginExternalCommands()
+
+ \since 5.14
+ */
+void QQuickWindow::endExternalCommands()
+{
+#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */
+ Q_D(QQuickWindow);
+ if (d->rhi && d->context && d->context->isValid()) {
+ QSGDefaultRenderContext *rc = static_cast<QSGDefaultRenderContext *>(d->context);
+ QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer();
+ if (cb)
+ cb->endExternal();
+ }
+#endif
+}
+
/*!
\qmlproperty string Window::title
@@ -5018,6 +5297,10 @@ void QQuickWindow::setSceneGraphBackend(QSGRendererInterface::GraphicsApi api)
default:
break;
}
+#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */
+ if (QSGRendererInterface::isApiRhiBased(api))
+ QSGRhiSupport::configure(api);
+#endif
}
/*!
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index 53fe0a4c4b..ab3046611f 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -66,6 +66,7 @@ class QQuickRenderControl;
class QSGRectangleNode;
class QSGImageNode;
class QSGNinePatchNode;
+class QRhi;
class Q_QUICK_EXPORT QQuickWindow : public QWindow
{
@@ -135,6 +136,13 @@ public:
#if QT_CONFIG(opengl)
void resetOpenGLState();
#endif
+ struct GraphicsStateInfo {
+ int currentFrameSlot = 0;
+ int framesInFlight = 0;
+ };
+ const GraphicsStateInfo *graphicsStateInfo();
+ void beginExternalCommands();
+ void endExternalCommands();
QQmlIncubationController *incubationController() const;
#if QT_CONFIG(accessibility)
@@ -198,6 +206,8 @@ Q_SIGNALS:
Q_REVISION(1) void activeFocusItemChanged();
Q_REVISION(2) void sceneGraphError(QQuickWindow::SceneGraphError error, const QString &message);
+ Q_REVISION(14) void beforeRenderPassRecording();
+ Q_REVISION(14) void afterRenderPassRecording();
public Q_SLOTS:
void update();
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index b4b456fbaa..becbae7fe3 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -82,6 +82,10 @@ class QQuickWindowPrivate;
class QQuickWindowRenderLoop;
class QSGRenderLoop;
class QTouchEvent;
+class QRhi;
+class QRhiSwapChain;
+class QRhiRenderBuffer;
+class QRhiRenderPassDescriptor;
//Make it easy to identify and customize the root item if needed
class QQuickRootItem : public QQuickItem
@@ -215,7 +219,7 @@ public:
void polishItems();
void forcePolish();
void syncSceneGraph();
- void renderSceneGraph(const QSize &size);
+ void renderSceneGraph(const QSize &size, const QSize &surfaceSize = QSize());
bool isRenderable() const;
@@ -317,6 +321,9 @@ public:
QString *untranslatedMessage,
bool isEs);
+ static void emitBeforeRenderPassRecording(void *ud);
+ static void emitAfterRenderPassRecording(void *ud);
+
QMutex renderJobMutex;
QList<QRunnable *> beforeSynchronizingJobs;
QList<QRunnable *> afterSynchronizingJobs;
@@ -326,6 +333,15 @@ public:
void runAndClearJobs(QList<QRunnable *> *jobs);
+ QQuickWindow::GraphicsStateInfo rhiStateInfo;
+ QRhi *rhi = nullptr;
+ QRhiSwapChain *swapchain = nullptr;
+ QRhiRenderBuffer *depthStencilForSwapchain = nullptr;
+ QRhiRenderPassDescriptor *rpDescForSwapchain = nullptr;
+ uint hasActiveSwapchain : 1;
+ uint hasRenderableSwapchain : 1;
+ uint swapchainJustBecameRenderable : 1;
+
private:
static void cleanupNodesOnShutdown(QQuickItem *);
};
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index 2b109c0897..7b3874dbfe 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -214,6 +214,7 @@ void QQuickWindowModule::defineModule()
qmlRegisterRevision<QWindow,13>(uri, 2, 13);
qmlRegisterRevision<QQuickWindow,13>(uri, 2, 13);
qmlRegisterType<QQuickWindowQmlImpl,13>(uri, 2, 13, "Window");
+ qmlRegisterRevision<QQuickWindow,14>(uri, 2, 14);
}
QT_END_NAMESPACE