aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2013-12-16 17:05:21 +0100
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2013-12-16 17:05:21 +0100
commit13e88fe2b9b1680cb161a249289c3ba998f08c0c (patch)
tree496a9d88c69b441e8c88aa0416b327faca3a1532 /src/quick
parenta2dad3ddee9c4bf274a7c6469342e4104605ceeb (diff)
parent470ba767663e4ad9d3183fb56ee89361354dfefb (diff)
Merge remote-tracking branch 'origin/stable' into dev
Conflicts: src/quick/items/qquickitem.cpp src/quick/items/qquicktext.cpp tests/auto/quick/qquicklistview/tst_qquicklistview.cpp Change-Id: I0bc5786098193c2c40b6fd8905de75d90f6ed0cf
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/items/context2d/qquickcanvascontext_p.h2
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp64
-rw-r--r--src/quick/items/context2d/qquickcanvasitem_p.h8
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp60
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h6
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp34
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h2
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp193
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture_p.h70
-rw-r--r--src/quick/items/items.pri1
-rw-r--r--src/quick/items/qquickflickable.cpp126
-rw-r--r--src/quick/items/qquickflickablebehavior_p.h105
-rw-r--r--src/quick/items/qquickitem.cpp15
-rw-r--r--src/quick/items/qquickitem_p.h2
-rw-r--r--src/quick/items/qquickitemview_p.h15
-rw-r--r--src/quick/items/qquicklistview.cpp68
-rw-r--r--src/quick/items/qquickloader.cpp5
-rw-r--r--src/quick/items/qquickloader_p_p.h1
-rw-r--r--src/quick/items/qquickmousearea.cpp6
-rw-r--r--src/quick/items/qquickpathview.cpp17
-rw-r--r--src/quick/items/qquickshadereffectnode.cpp1
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp15
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h1
-rw-r--r--src/quick/items/qquicktext.cpp98
-rw-r--r--src/quick/items/qquicktextinput.cpp2
-rw-r--r--src/quick/items/qquickwindow.cpp44
-rw-r--r--src/quick/items/qquickwindow_p.h1
-rw-r--r--src/quick/items/qquickwindowmodule.cpp80
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp14
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h4
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer.cpp6
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp2
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp76
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop_p.h2
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp4
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture.cpp1
-rw-r--r--src/quick/util/qquickapplication.cpp2
-rw-r--r--src/quick/util/qquickpixmapcache.cpp22
38 files changed, 738 insertions, 437 deletions
diff --git a/src/quick/items/context2d/qquickcanvascontext_p.h b/src/quick/items/context2d/qquickcanvascontext_p.h
index 559f41e546..2d8fbb5f85 100644
--- a/src/quick/items/context2d/qquickcanvascontext_p.h
+++ b/src/quick/items/context2d/qquickcanvascontext_p.h
@@ -71,8 +71,6 @@ public:
virtual void setV8Engine(QV8Engine *engine) = 0;
virtual QV4::ReturnedValue v4value() const = 0;
- virtual QSGDynamicTexture *texture() const = 0;
-
virtual QImage toImage(const QRectF& bounds) = 0;
Q_SIGNALS:
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index ee1b5f316c..be9c592228 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -44,8 +44,10 @@
#include <private/qquickitem_p.h>
#include <private/qquickcanvascontext_p.h>
#include <private/qquickcontext2d_p.h>
+#include <private/qquickcontext2dtexture_p.h>
#include <qsgsimpletexturenode.h>
#include <QtQuick/private/qquickpixmapcache_p.h>
+#include <QtGui/QGuiApplication>
#include <qqmlinfo.h>
#include <private/qqmlengine_p.h>
@@ -58,19 +60,15 @@
QT_BEGIN_NAMESPACE
-QQuickCanvasPixmap::QQuickCanvasPixmap(const QImage& image, QQuickWindow *window)
+QQuickCanvasPixmap::QQuickCanvasPixmap(const QImage& image)
: m_pixmap(0)
, m_image(image)
- , m_texture(0)
- , m_window(window)
{
}
-QQuickCanvasPixmap::QQuickCanvasPixmap(QQuickPixmap *pixmap, QQuickWindow *window)
+QQuickCanvasPixmap::QQuickCanvasPixmap(QQuickPixmap *pixmap)
: m_pixmap(pixmap)
- , m_texture(0)
- , m_window(window)
{
}
@@ -78,8 +76,6 @@ QQuickCanvasPixmap::QQuickCanvasPixmap(QQuickPixmap *pixmap, QQuickWindow *windo
QQuickCanvasPixmap::~QQuickCanvasPixmap()
{
delete m_pixmap;
- if (m_texture)
- m_texture->deleteLater();
}
qreal QQuickCanvasPixmap::width() const
@@ -105,18 +101,6 @@ bool QQuickCanvasPixmap::isValid() const
return !m_image.isNull();
}
-QSGTexture *QQuickCanvasPixmap::texture()
-{
- if (!m_texture) {
- if (m_pixmap) {
- Q_ASSERT(m_pixmap->textureFactory());
- m_texture = m_pixmap->textureFactory()->createTexture(m_window);
- } else {
- m_texture = m_window->createTextureFromImage(m_image, QQuickWindow::TextureCanUseAtlas);
- }
- }
- return m_texture;
-}
QImage QQuickCanvasPixmap::image()
{
if (m_image.isNull() && m_pixmap)
@@ -194,7 +178,7 @@ QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
, hasCanvasWindow(false)
, available(false)
, renderTarget(QQuickCanvasItem::Image)
- , renderStrategy(QQuickCanvasItem::Cooperative)
+ , renderStrategy(QQuickCanvasItem::Immediate)
{
implicitAntialiasing = true;
}
@@ -246,10 +230,14 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
The Canvas.FramebufferObject render target utilizes OpenGL hardware
acceleration rather than rendering into system memory, which in many cases
- results in faster rendering.
+ results in faster rendering. Canvas.FramebufferObject relies on the
+ OpenGL extensions \c GL_EXT_framebuffer_multisample and
+ \c GL_EXT_framebuffer_blit for antialiasing. It will also use more
+ graphics memory when rendering strategy is anything other than
+ Canvas.Cooperative.
The default render target is Canvas.Image and the default renderStrategy is
- Canvas.Cooperative.
+ Canvas.Immediate.
\section1 Tiled Canvas
The Canvas item supports tiled rendering by setting \l canvasSize, \l tileSize
@@ -489,7 +477,7 @@ void QQuickCanvasItem::setCanvasWindow(const QRectF& rect)
context will choose appropriate options and Canvas will signal the change
to the properties.
- The default render target is \c Canvas.FramebufferObject.
+ The default render target is \c Canvas.Image.
*/
QQuickCanvasItem::RenderTarget QQuickCanvasItem::renderTarget() const
{
@@ -531,7 +519,7 @@ void QQuickCanvasItem::setRenderTarget(QQuickCanvasItem::RenderTarget target)
the GUI thread. Selecting \c Canvas.Cooperative, does not guarantee
rendering will occur on a thread separate from the GUI thread.
- The default value is \c Canvas.Cooperative.
+ The default value is \c Canvas.Immediate.
\sa renderTarget
*/
@@ -689,6 +677,15 @@ void QQuickCanvasItem::updatePolish()
}
}
+class QQuickCanvasNode : public QSGSimpleTextureNode
+{
+public:
+ ~QQuickCanvasNode()
+ {
+ delete texture();
+ }
+};
+
QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
Q_D(QQuickCanvasItem);
@@ -698,9 +695,9 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
return 0;
}
- QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode*>(oldNode);
+ QQuickCanvasNode *node = static_cast<QQuickCanvasNode*>(oldNode);
if (!node)
- node = new QSGSimpleTextureNode;
+ node = new QQuickCanvasNode();
if (d->smooth)
node->setFiltering(QSGTexture::Linear);
@@ -712,8 +709,15 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
d->context->flush();
}
- node->setTexture(d->context->texture());
- node->markDirty(QSGNode::DirtyMaterial);
+ QQuickContext2D *ctx = qobject_cast<QQuickContext2D *>(d->context);
+ QQuickContext2DTexture *factory = ctx->texture();
+ QSGTexture *texture = factory->textureForNextFrame(node->texture());
+ if (!texture) {
+ delete node;
+ return 0;
+ }
+
+ node->setTexture(texture);
node->setRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
return node;
}
@@ -916,7 +920,7 @@ void QQuickCanvasItem::loadImage(const QUrl& url)
if (!d->pixmaps.contains(fullPathUrl)) {
QQuickPixmap* pix = new QQuickPixmap();
QQmlRefPointer<QQuickCanvasPixmap> canvasPix;
- canvasPix.take(new QQuickCanvasPixmap(pix, d->window));
+ canvasPix.take(new QQuickCanvasPixmap(pix));
d->pixmaps.insert(fullPathUrl, canvasPix);
pix->load(qmlEngine(this)
diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h
index 2ec36cfe73..3baf68d418 100644
--- a/src/quick/items/context2d/qquickcanvasitem_p.h
+++ b/src/quick/items/context2d/qquickcanvasitem_p.h
@@ -52,17 +52,15 @@ QT_BEGIN_NAMESPACE
class QQuickCanvasContext;
class QQuickCanvasItemPrivate;
-class QSGTexture;
class QQuickPixmap;
class QQuickCanvasPixmap : public QQmlRefCount
{
public:
- QQuickCanvasPixmap(const QImage& image, QQuickWindow *window);
- QQuickCanvasPixmap(QQuickPixmap *pixmap, QQuickWindow *window);
+ QQuickCanvasPixmap(const QImage& image);
+ QQuickCanvasPixmap(QQuickPixmap *pixmap);
~QQuickCanvasPixmap();
- QSGTexture *texture();
QImage image();
qreal width() const;
@@ -73,8 +71,6 @@ public:
private:
QQuickPixmap *m_pixmap;
QImage m_image;
- QSGTexture *m_texture;
- QQuickWindow *m_window;
};
class QQuickCanvasItem : public QQuickItem
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 2a9e0f2ac2..b6eb2db33d 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -484,7 +484,7 @@ public:
QQuickJSContext2D(QV4::ExecutionEngine *engine)
: QV4::Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
QQuickContext2D* context;
@@ -653,7 +653,7 @@ public:
, patternRepeatX(false)
, patternRepeatY(false)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
QBrush brush;
bool patternRepeatX:1;
@@ -870,7 +870,7 @@ struct QQuickJSContext2DPixelData : public QV4::Object
QQuickJSContext2DPixelData(QV4::ExecutionEngine *engine)
: QV4::Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
flags &= ~SimpleArray;
}
@@ -893,7 +893,7 @@ struct QQuickJSContext2DImageData : public QV4::Object
QQuickJSContext2DImageData(QV4::ExecutionEngine *engine)
: QV4::Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
pixelData = QV4::Primitive::undefinedValue();
QV4::Scope scope(engine);
@@ -2985,14 +2985,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
} else if (QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(qobjectWrapper->object())) {
QImage img = canvas->toImage();
if (!img.isNull())
- pixmap.take(new QQuickCanvasPixmap(img, canvas->window()));
+ pixmap.take(new QQuickCanvasPixmap(img));
} else {
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
} else if (QV4::Referenced<QQuickJSContext2DImageData> imageData = arg->asRef<QQuickJSContext2DImageData>()) {
QV4::Scoped<QQuickJSContext2DPixelData> pix(scope, imageData->pixelData.as<QQuickJSContext2DPixelData>());
if (pix && !pix->image.isNull()) {
- pixmap.take(new QQuickCanvasPixmap(pix->image, r->context->canvas()->window()));
+ pixmap.take(new QQuickCanvasPixmap(pix->image));
} else {
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
@@ -3165,7 +3165,7 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(QV4::Managed *m, uint
QV4::Scope scope(v4);
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, m->as<QQuickJSContext2DPixelData>());
if (!m)
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4)) {
if (hasProperty)
@@ -3200,7 +3200,7 @@ void QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const Q
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, m->as<QQuickJSContext2DPixelData>());
if (!r) {
- v4->current->throwTypeError();
+ v4->currentContext()->throwTypeError();
return;
}
@@ -4084,6 +4084,15 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
QQuickWindow *window = canvasItem->window();
m_renderStrategy = canvasItem->renderStrategy();
+#ifdef Q_OS_WIN
+ if (m_renderTarget == QQuickCanvasItem::FramebufferObject
+ && (m_renderStrategy != QQuickCanvasItem::Cooperative)) {
+ // On windows a context needs to be unbound set up sharing, so
+ // for simplicity we disallow FBO + !coop here.
+ m_renderTarget = QQuickCanvasItem::Image;
+ }
+#endif
+
switch (m_renderTarget) {
case QQuickCanvasItem::Image:
m_texture = new QQuickContext2DImageTexture;
@@ -4099,6 +4108,7 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_texture->setCanvasSize(canvasItem->canvasSize().toSize());
m_texture->setSmooth(canvasItem->smooth());
m_texture->setAntialiasing(canvasItem->antialiasing());
+ m_texture->setOnCustomThread(m_renderStrategy == QQuickCanvasItem::Threaded);
m_thread = QThread::currentThread();
QThread *renderThread = m_thread;
@@ -4129,28 +4139,31 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
void QQuickContext2D::prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth, bool antialiasing)
{
- QMetaObject::invokeMethod(m_texture
- , "canvasChanged"
- , Qt::AutoConnection
- , Q_ARG(QSize, canvasSize)
- , Q_ARG(QSize, tileSize)
- , Q_ARG(QRect, canvasWindow)
- , Q_ARG(QRect, dirtyRect)
- , Q_ARG(bool, smooth)
- , Q_ARG(bool, antialiasing));
+ if (m_texture->thread() == QThread::currentThread()) {
+ m_texture->canvasChanged(canvasSize, tileSize, canvasWindow, dirtyRect, smooth, antialiasing);
+ } else {
+ QEvent *e = new QQuickContext2DTexture::CanvasChangeEvent(canvasSize,
+ tileSize,
+ canvasWindow,
+ dirtyRect,
+ smooth,
+ antialiasing);
+ QCoreApplication::postEvent(m_texture, e);
+ }
}
void QQuickContext2D::flush()
{
- if (m_buffer)
- QMetaObject::invokeMethod(m_texture,
- "paint",
- Qt::AutoConnection,
- Q_ARG(QQuickContext2DCommandBuffer*, m_buffer));
+ if (m_buffer) {
+ if (m_texture->thread() == QThread::currentThread())
+ m_texture->paint(m_buffer);
+ else
+ QCoreApplication::postEvent(m_texture, new QQuickContext2DTexture::PaintEvent(m_buffer));
+ }
m_buffer = new QQuickContext2DCommandBuffer();
}
-QSGDynamicTexture *QQuickContext2D::texture() const
+QQuickContext2DTexture *QQuickContext2D::texture() const
{
return m_texture;
}
@@ -4164,6 +4177,7 @@ QImage QQuickContext2D::toImage(const QRectF& bounds)
qWarning() << "Pixel readback is not supported in Cooperative mode, please try Threaded or Immediate mode";
return QImage();
} else {
+ QCoreApplication::postEvent(m_texture, new QEvent(QEvent::Type(QEvent::User + 10)));
QMetaObject::invokeMethod(m_texture,
"grabImage",
Qt::BlockingQueuedConnection,
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index 4bef50d9cd..6399da3dee 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -74,6 +74,8 @@ class QOpenGLContext;
class QQuickContext2D : public QQuickCanvasContext
{
+ Q_OBJECT
+
public:
Q_DISABLE_COPY(QQuickContext2D)
@@ -171,8 +173,8 @@ public:
void prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth, bool antialiasing);
void flush();
void sync();
- QThread *thread() const {return m_thread;}
- QSGDynamicTexture *texture() const;
+ QThread *thread() const { return m_thread; }
+ QQuickContext2DTexture *texture() const;
QImage toImage(const QRectF& bounds);
QV4::ReturnedValue v4value() const;
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
index d2f4e3317d..06a0713365 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
@@ -420,38 +420,8 @@ void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& s
Q_ASSERT(!pix.isNull());
const bool hasShadow = HAS_SHADOW(state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor);
- if (p->paintEngine()->type() != QPaintEngine::OpenGL2 || hasShadow){
- //TODO: generate shadow blur with shaders
- qt_drawImage(p, state, pix->image(), sr, dr, hasShadow);
- } else if (pix->texture()){
- QSGTexture *tex = pix->texture();
- QSGDynamicTexture *dynamicTexture = qobject_cast<QSGDynamicTexture *>(tex);
- if (dynamicTexture)
- dynamicTexture->updateTexture();
-
- if (tex->textureId()) {
-
- if (sr.width() < 0)
- sr.setWidth(tex->textureSize().width());
- if (sr.height() < 0)
- sr.setHeight(tex->textureSize().height());
-
- if (dr.width() < 0)
- dr.setWidth(sr.width());
- if (dr.height() < 0)
- dr.setHeight(sr.height());
-
- qreal srBottom = sr.bottom();
- sr.setBottom(sr.top());
- sr.setTop(srBottom);
-
- tex->bind();
- if (p->paintEngine()->type() == QPaintEngine::OpenGL2) {
- QOpenGL2PaintEngineEx *engine = static_cast<QOpenGL2PaintEngineEx *>(p->paintEngine());
- engine->drawTexture(dr, tex->textureId(), tex->textureSize(), sr);
- }
- }
- }
+ //TODO: generate shadow blur with shaders
+ qt_drawImage(p, state, pix->image(), sr, dr, hasShadow);
break;
}
case QQuickContext2D::GetImageData:
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
index 29cdc73708..9e79333a0c 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
@@ -58,8 +58,6 @@ public:
void reset();
void clear();
- void lockQueue() { queueLock.lock(); }
- void unlockQueue() { queueLock.unlock(); }
inline int size() {return commands.size();}
inline bool isEmpty() const {return commands.isEmpty(); }
inline bool hasNext() const {return cmdIdx < commands.size(); }
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index 8dc9978089..8dd48b4988 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -50,6 +50,7 @@
#include <QOpenGLFramebufferObject>
#include <QOpenGLFramebufferObjectFormat>
#include <QtCore/QThread>
+#include <QtGui/QGuiApplication>
QT_BEGIN_NAMESPACE
@@ -90,7 +91,6 @@ struct GLAcquireContext {
QQuickContext2DTexture::QQuickContext2DTexture()
: m_context(0)
, m_item(0)
- , m_dirtyCanvas(false)
, m_canvasWindowChanged(false)
, m_dirtyTexture(false)
, m_smooth(true)
@@ -105,23 +105,20 @@ QQuickContext2DTexture::~QQuickContext2DTexture()
clearTiles();
}
-QSize QQuickContext2DTexture::textureSize() const
-{
- return m_canvasWindow.size();
-}
-
void QQuickContext2DTexture::markDirtyTexture()
{
+ if (m_onCustomThread)
+ m_mutex.lock();
m_dirtyTexture = true;
- updateTexture();
emit textureChanged();
+ if (m_onCustomThread)
+ m_mutex.unlock();
}
bool QQuickContext2DTexture::setCanvasSize(const QSize &size)
{
if (m_canvasSize != size) {
m_canvasSize = size;
- m_dirtyCanvas = true;
return true;
}
return false;
@@ -131,7 +128,6 @@ bool QQuickContext2DTexture::setTileSize(const QSize &size)
{
if (m_tileSize != size) {
m_tileSize = size;
- m_dirtyCanvas = true;
return true;
}
return false;
@@ -195,7 +191,6 @@ void QQuickContext2DTexture::canvasChanged(const QSize& canvasSize, const QSize&
if (canvasSize == canvasWindow.size()) {
m_tiledCanvas = false;
- m_dirtyCanvas = false;
} else {
m_tiledCanvas = true;
}
@@ -309,7 +304,6 @@ QRect QQuickContext2DTexture::createTiles(const QRect& window)
m_tiles.clear();
if (window.isEmpty()) {
- m_dirtyCanvas = false;
return QRect();
}
@@ -351,7 +345,6 @@ QRect QQuickContext2DTexture::createTiles(const QRect& window)
qDeleteAll(oldTiles);
- m_dirtyCanvas = false;
return r;
}
@@ -366,6 +359,20 @@ QSize QQuickContext2DTexture::adjustedTileSize(const QSize &ts)
return ts;
}
+bool QQuickContext2DTexture::event(QEvent *e)
+{
+ if ((int) e->type() == QEvent::User + 1) {
+ PaintEvent *pe = static_cast<PaintEvent *>(e);
+ paint(pe->buffer);
+ return true;
+ } else if ((int) e->type() == QEvent::User + 2) {
+ CanvasChangeEvent *ce = static_cast<CanvasChangeEvent *>(e);
+ canvasChanged(ce->canvasSize, ce->tileSize, ce->canvasWindow, ce->dirtyRect, ce->smooth, ce->antialiasing);
+ return true;
+ }
+ return QObject::event(e);
+}
+
static inline QSize npotAdjustedSize(const QSize &size)
{
static bool checked = false;
@@ -391,6 +398,9 @@ QQuickContext2DFBOTexture::QQuickContext2DFBOTexture()
, m_multisampledFbo(0)
, m_paint_device(0)
{
+ m_displayTextures[0] = 0;
+ m_displayTextures[1] = 0;
+ m_displayTexture = -1;
}
QQuickContext2DFBOTexture::~QQuickContext2DFBOTexture()
@@ -403,17 +413,52 @@ QQuickContext2DFBOTexture::~QQuickContext2DFBOTexture()
delete m_fbo;
delete m_multisampledFbo;
delete m_paint_device;
+
+ glDeleteTextures(2, m_displayTextures);
}
-QSize QQuickContext2DFBOTexture::adjustedTileSize(const QSize &ts)
+QSGTexture *QQuickContext2DFBOTexture::textureForNextFrame(QSGTexture *lastTexture)
{
- return npotAdjustedSize(ts);
+ QSGPlainTexture *texture = static_cast<QSGPlainTexture *>(lastTexture);
+
+ if (m_onCustomThread)
+ m_mutex.lock();
+
+ if (m_fbo) {
+ if (!texture) {
+ texture = new QSGPlainTexture();
+ texture->setHasMipmaps(false);
+ texture->setHasAlphaChannel(true);
+ texture->setOwnsTexture(false);
+ m_dirtyTexture = true;
+ }
+
+ if (m_dirtyTexture) {
+ if (!m_context->glContext()) {
+ // on a rendering thread, use the fbo directly...
+ texture->setTextureId(m_fbo->texture());
+ } else {
+ // on GUI or custom thread, use display textures...
+ m_displayTexture = m_displayTexture == 0 ? 1 : 0;
+ texture->setTextureId(m_displayTextures[m_displayTexture]);
+ }
+ texture->setTextureSize(m_fbo->size());
+ m_dirtyTexture = false;
+ }
+
+ }
+
+ if (m_onCustomThread) {
+ m_condition.wakeOne();
+ m_mutex.unlock();
+ }
+
+ return texture;
}
-void QQuickContext2DFBOTexture::bind()
+QSize QQuickContext2DFBOTexture::adjustedTileSize(const QSize &ts)
{
- glBindTexture(GL_TEXTURE_2D, textureId());
- updateBindOptions();
+ return npotAdjustedSize(ts);
}
QRectF QQuickContext2DFBOTexture::normalizedTextureSubRect() const
@@ -424,20 +469,6 @@ QRectF QQuickContext2DFBOTexture::normalizedTextureSubRect() const
, qreal(m_canvasWindow.height()) / m_fboSize.height());
}
-
-int QQuickContext2DFBOTexture::textureId() const
-{
- return m_fbo? m_fbo->texture() : 0;
-}
-
-
-bool QQuickContext2DFBOTexture::updateTexture()
-{
- bool textureUpdated = m_dirtyTexture;
- m_dirtyTexture = false;
- return textureUpdated;
-}
-
QQuickContext2DTile* QQuickContext2DFBOTexture::createTile() const
{
return new QQuickContext2DFBOTile();
@@ -461,7 +492,6 @@ bool QQuickContext2DFBOTexture::doMultisampling() const
void QQuickContext2DFBOTexture::grabImage(const QRectF& rf)
{
Q_ASSERT(rf.isValid());
-
if (!m_fbo) {
m_context->setGrabbedImage(QImage());
return;
@@ -531,7 +561,6 @@ QPaintDevice* QQuickContext2DFBOTexture::beginPainting()
} else {
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
-
m_fbo = new QOpenGLFramebufferObject(m_fboSize, format);
}
}
@@ -541,7 +570,6 @@ QPaintDevice* QQuickContext2DFBOTexture::beginPainting()
else
m_fbo->bind();
-
if (!m_paint_device) {
QOpenGLPaintDevice *gl_device = new QOpenGLPaintDevice(m_fbo->size());
gl_device->setPaintFlipped(true);
@@ -557,25 +585,47 @@ void QQuickContext2DFBOTexture::endPainting()
QQuickContext2DTexture::endPainting();
if (m_multisampledFbo)
QOpenGLFramebufferObject::blitFramebuffer(m_fbo, m_multisampledFbo);
+
+ if (m_context->glContext()) {
+ /* When rendering happens on the render thread, the fbo's texture is
+ * used directly for display. If we are on the GUI thread or a
+ * dedicated Canvas render thread, we need to decouple the FBO from
+ * the texture we are displaying in the SG rendering thread to avoid
+ * stalls and read/write issues in the GL pipeline as the FBO's texture
+ * could then potentially be used in different threads.
+ *
+ * We could have gotten away with only one display texture, but this
+ * would have implied that beginPainting would have to wait for SG
+ * to release that texture.
+ */
+
+ if (m_onCustomThread)
+ m_mutex.lock();
+
+ if (m_displayTextures[0] == 0) {
+ m_displayTexture = 1;
+ glGenTextures(2, m_displayTextures);
+ }
+
+ m_fbo->bind();
+ GLuint target = m_displayTexture == 0 ? 1 : 0;
+ glBindTexture(GL_TEXTURE_2D, m_displayTextures[target]);
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, m_fbo->width(), m_fbo->height(), 0);
+
+ if (m_onCustomThread)
+ m_mutex.unlock();
+ }
+
+ m_fbo->bindDefault();
}
QQuickContext2DImageTexture::QQuickContext2DImageTexture()
: QQuickContext2DTexture()
- , m_texture(0)
{
}
QQuickContext2DImageTexture::~QQuickContext2DImageTexture()
{
- if (m_texture && m_texture->thread() != QThread::currentThread())
- m_texture->deleteLater();
- else
- delete m_texture;
-}
-
-int QQuickContext2DImageTexture::textureId() const
-{
- return imageTexture()->textureId();
}
QQuickCanvasItem::RenderTarget QQuickContext2DImageTexture::renderTarget() const
@@ -583,22 +633,6 @@ QQuickCanvasItem::RenderTarget QQuickContext2DImageTexture::renderTarget() const
return QQuickCanvasItem::Image;
}
-void QQuickContext2DImageTexture::bind()
-{
- imageTexture()->setFiltering(filtering());
- imageTexture()->bind();
-}
-
-bool QQuickContext2DImageTexture::updateTexture()
-{
- bool textureUpdated = m_dirtyTexture;
- if (m_dirtyTexture) {
- imageTexture()->setImage(m_image);
- m_dirtyTexture = false;
- }
- return textureUpdated;
-}
-
QQuickContext2DTile* QQuickContext2DImageTexture::createTile() const
{
return new QQuickContext2DImageTile();
@@ -608,19 +642,32 @@ void QQuickContext2DImageTexture::grabImage(const QRectF& rf)
{
Q_ASSERT(rf.isValid());
Q_ASSERT(m_context);
- QImage grabbed = m_image.copy(rf.toRect());
+ QImage grabbed = m_displayImage.copy(rf.toRect());
m_context->setGrabbedImage(grabbed);
}
-QSGPlainTexture *QQuickContext2DImageTexture::imageTexture() const
+QSGTexture *QQuickContext2DImageTexture::textureForNextFrame(QSGTexture *last)
{
- if (!m_texture) {
- QQuickContext2DImageTexture *that = const_cast<QQuickContext2DImageTexture *>(this);
- that->m_texture = new QSGPlainTexture;
- that->m_texture->setOwnsTexture(true);
- that->m_texture->setHasMipmaps(false);
+ QSGPlainTexture *texture = static_cast<QSGPlainTexture *>(last);
+
+ if (m_onCustomThread)
+ m_mutex.lock();
+
+ if (!texture) {
+ texture = new QSGPlainTexture();
+ texture->setHasMipmaps(false);
+ texture->setHasAlphaChannel(true);
+ m_dirtyTexture = true;
+ }
+ if (m_dirtyTexture) {
+ texture->setImage(m_displayImage);
+ m_dirtyTexture = false;
}
- return m_texture;
+
+ if (m_onCustomThread)
+ m_mutex.unlock();
+
+ return texture;
}
QPaintDevice* QQuickContext2DImageTexture::beginPainting()
@@ -639,6 +686,16 @@ QPaintDevice* QQuickContext2DImageTexture::beginPainting()
return &m_image;
}
+void QQuickContext2DImageTexture::endPainting()
+{
+ QQuickContext2DTexture::endPainting();
+ if (m_onCustomThread)
+ m_mutex.lock();
+ m_displayImage = m_image;
+ if (m_onCustomThread)
+ m_mutex.unlock();
+}
+
void QQuickContext2DImageTexture::compositeTile(QQuickContext2DTile* tile)
{
Q_ASSERT(!tile->dirty());
diff --git a/src/quick/items/context2d/qquickcontext2dtexture_p.h b/src/quick/items/context2d/qquickcontext2dtexture_p.h
index 2a5b7a318a..cf0e8e3fa9 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture_p.h
+++ b/src/quick/items/context2d/qquickcontext2dtexture_p.h
@@ -58,16 +58,44 @@ QT_BEGIN_NAMESPACE
class QQuickContext2DTile;
class QQuickContext2DCommandBuffer;
-class QQuickContext2DTexture : public QSGDynamicTexture
+class QQuickContext2DTexture : public QObject
{
Q_OBJECT
public:
+ class PaintEvent : public QEvent {
+ public:
+ PaintEvent(QQuickContext2DCommandBuffer *b) : QEvent(QEvent::Type(QEvent::User + 1)), buffer(b) {}
+ QQuickContext2DCommandBuffer *buffer;
+ };
+
+ class CanvasChangeEvent : public QEvent {
+ public:
+ CanvasChangeEvent(const QSize &cSize,
+ const QSize &tSize,
+ const QRect &cWindow,
+ const QRect &dRect,
+ bool sm,
+ bool aa)
+ : QEvent(QEvent::Type(QEvent::User + 2))
+ , canvasSize(cSize)
+ , tileSize(tSize)
+ , canvasWindow(cWindow)
+ , dirtyRect(dRect)
+ , smooth(sm)
+ , antialiasing(aa)
+ {
+ }
+ QSize canvasSize;
+ QSize tileSize;
+ QRect canvasWindow;
+ QRect dirtyRect;
+ bool smooth;
+ bool antialiasing;
+ };
+
QQuickContext2DTexture();
~QQuickContext2DTexture();
- virtual bool hasAlphaChannel() const {return true;}
- virtual bool hasMipmaps() const {return false;}
- virtual QSize textureSize() const;
virtual QQuickCanvasItem::RenderTarget renderTarget() const = 0;
static QRect tiledRect(const QRectF& window, const QSize& tileSize);
@@ -78,15 +106,20 @@ public:
void setAntialiasing(bool antialiasing);
bool setDirtyRect(const QRect &dirtyRect);
bool canvasDestroyed();
+ void setOnCustomThread(bool is) { m_onCustomThread = is; }
+
+ // Called during sync() on the scene graph thread while GUI is blocked.
+ virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame) = 0;
+ bool event(QEvent *e);
Q_SIGNALS:
void textureChanged();
public Q_SLOTS:
- void markDirtyTexture();
- void setItem(QQuickCanvasItem* item);
void canvasChanged(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth, bool antialiasing);
void paint(QQuickContext2DCommandBuffer *ccb);
+ void markDirtyTexture();
+ void setItem(QQuickCanvasItem* item);
virtual void grabImage(const QRectF& region = QRectF()) = 0;
protected:
@@ -110,13 +143,16 @@ protected:
QSize m_tileSize;
QRect m_canvasWindow;
- uint m_dirtyCanvas : 1;
+ QMutex m_mutex;
+ QWaitCondition m_condition;
+
uint m_canvasWindowChanged : 1;
uint m_dirtyTexture : 1;
uint m_smooth : 1;
uint m_antialiasing : 1;
uint m_tiledCanvas : 1;
uint m_painting : 1;
+ uint m_onCustomThread : 1; // Not GUI and not SGRender
};
class QQuickContext2DFBOTexture : public QQuickContext2DTexture
@@ -126,17 +162,16 @@ class QQuickContext2DFBOTexture : public QQuickContext2DTexture
public:
QQuickContext2DFBOTexture();
~QQuickContext2DFBOTexture();
- virtual int textureId() const;
- virtual bool updateTexture();
virtual QQuickContext2DTile* createTile() const;
virtual QPaintDevice* beginPainting();
virtual void endPainting();
QRectF normalizedTextureSubRect() const;
virtual QQuickCanvasItem::RenderTarget renderTarget() const;
virtual void compositeTile(QQuickContext2DTile* tile);
- virtual void bind();
QSize adjustedTileSize(const QSize &ts);
+ QSGTexture *textureForNextFrame(QSGTexture *);
+
public Q_SLOTS:
virtual void grabImage(const QRectF& region = QRectF());
@@ -144,10 +179,12 @@ private:
bool doMultisampling() const;
QOpenGLFramebufferObject *m_fbo;
QOpenGLFramebufferObject *m_multisampledFbo;
- QMutex m_mutex;
- QWaitCondition m_condition;
QSize m_fboSize;
QPaintDevice *m_paint_device;
+
+
+ GLuint m_displayTextures[2];
+ int m_displayTexture;
};
class QSGPlainTexture;
@@ -158,24 +195,23 @@ class QQuickContext2DImageTexture : public QQuickContext2DTexture
public:
QQuickContext2DImageTexture();
~QQuickContext2DImageTexture();
- virtual int textureId() const;
- virtual void bind();
virtual QQuickCanvasItem::RenderTarget renderTarget() const;
- virtual bool updateTexture();
virtual QQuickContext2DTile* createTile() const;
virtual QPaintDevice* beginPainting();
+ virtual void endPainting();
virtual void compositeTile(QQuickContext2DTile* tile);
+ virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame);
+
public Q_SLOTS:
virtual void grabImage(const QRectF& region = QRectF());
private:
- QSGPlainTexture *imageTexture() const;
QImage m_image;
+ QImage m_displayImage;
QPainter m_painter;
- QSGPlainTexture* m_texture;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index 3996512f9d..41cdb3526b 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -39,6 +39,7 @@ HEADERS += \
$$PWD/qquickpincharea_p_p.h \
$$PWD/qquickflickable_p.h \
$$PWD/qquickflickable_p_p.h \
+ $$PWD/qquickflickablebehavior_p.h \
$$PWD/qquicklistview_p.h \
$$PWD/qquickrepeater_p.h \
$$PWD/qquickrepeater_p_p.h \
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index ae174d86e0..fa18d4aa30 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -41,6 +41,7 @@
#include "qquickflickable_p.h"
#include "qquickflickable_p_p.h"
+#include "qquickflickablebehavior_p.h"
#include "qquickwindow.h"
#include "qquickwindow_p.h"
#include "qquickevents_p_p.h"
@@ -58,52 +59,6 @@
QT_BEGIN_NAMESPACE
-// The maximum number of pixels a flick can overshoot
-#ifndef QML_FLICK_OVERSHOOT
-#define QML_FLICK_OVERSHOOT 150
-#endif
-
-// The number of samples to use in calculating the velocity of a flick
-#ifndef QML_FLICK_SAMPLEBUFFER
-#define QML_FLICK_SAMPLEBUFFER 3
-#endif
-
-// The number of samples to discard when calculating the flick velocity.
-// Touch panels often produce inaccurate results as the finger is lifted.
-#ifndef QML_FLICK_DISCARDSAMPLES
-#define QML_FLICK_DISCARDSAMPLES 0
-#endif
-
-// The default maximum velocity of a flick.
-#ifndef QML_FLICK_DEFAULTMAXVELOCITY
-#define QML_FLICK_DEFAULTMAXVELOCITY 2500
-#endif
-
-// The default deceleration of a flick.
-#ifndef QML_FLICK_DEFAULTDECELERATION
-#define QML_FLICK_DEFAULTDECELERATION 1500
-#endif
-
-// How much faster to decelerate when overshooting
-#ifndef QML_FLICK_OVERSHOOTFRICTION
-#define QML_FLICK_OVERSHOOTFRICTION 8
-#endif
-
-// Multiflick acceleration minimum flick velocity threshold
-#ifndef QML_FLICK_MULTIFLICK_THRESHOLD
-#define QML_FLICK_MULTIFLICK_THRESHOLD 1250
-#endif
-
-// Multiflick acceleration minimum contentSize/viewSize ratio
-#ifndef QML_FLICK_MULTIFLICK_RATIO
-#define QML_FLICK_MULTIFLICK_RATIO 10
-#endif
-
-// Multiflick acceleration maximum velocity multiplier
-#ifndef QML_FLICK_MULTIFLICK_MAXBOOST
-#define QML_FLICK_MULTIFLICK_MAXBOOST 3.0
-#endif
-
// FlickThreshold determines how far the "mouse" must have moved
// before we perform a flick.
static const int FlickThreshold = 15;
@@ -508,16 +463,27 @@ void QQuickFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExt
data.vTime = timeline.time();
}
+static bool fuzzyLessThanOrEqualTo(qreal a, qreal b)
+{
+ if (a == 0.0 || b == 0.0) {
+ // qFuzzyCompare is broken
+ a += 1.0;
+ b += 1.0;
+ }
+ return a <= b || qFuzzyCompare(a, b);
+}
+
void QQuickFlickablePrivate::updateBeginningEnd()
{
Q_Q(QQuickFlickable);
bool atBoundaryChange = false;
// Vertical
- const int maxyextent = int(-q->maxYExtent());
+ const qreal maxyextent = -q->maxYExtent();
+ const qreal minyextent = -q->minYExtent();
const qreal ypos = -vData.move.value();
- bool atBeginning = (ypos <= -q->minYExtent());
- bool atEnd = (maxyextent <= ypos);
+ bool atBeginning = fuzzyLessThanOrEqualTo(ypos, minyextent);
+ bool atEnd = fuzzyLessThanOrEqualTo(maxyextent, ypos);
if (atBeginning != vData.atBeginning) {
vData.atBeginning = atBeginning;
@@ -529,10 +495,11 @@ void QQuickFlickablePrivate::updateBeginningEnd()
}
// Horizontal
- const int maxxextent = int(-q->maxXExtent());
+ const qreal maxxextent = -q->maxXExtent();
+ const qreal minxextent = -q->minXExtent();
const qreal xpos = -hData.move.value();
- atBeginning = (xpos <= -q->minXExtent());
- atEnd = (maxxextent <= xpos);
+ atBeginning = fuzzyLessThanOrEqualTo(xpos, minxextent);
+ atEnd = fuzzyLessThanOrEqualTo(maxxextent, xpos);
if (atBeginning != hData.atBeginning) {
hData.atBeginning = atBeginning;
@@ -1046,17 +1013,20 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
// the estimate to be altered
const qreal minY = vData.dragMinBound + vData.startMargin;
const qreal maxY = vData.dragMaxBound - vData.endMargin;
- if (newY > minY)
- newY = minY + (newY - minY) / 2;
- if (newY < maxY && maxY - minY <= 0)
- newY = maxY + (newY - maxY) / 2;
- if (boundsBehavior == QQuickFlickable::StopAtBounds && newY <= maxY) {
- newY = maxY;
- rejectY = vData.pressPos == maxY && dy < 0;
- }
- if (boundsBehavior == QQuickFlickable::StopAtBounds && newY >= minY) {
- newY = minY;
- rejectY = vData.pressPos == minY && dy > 0;
+ if (boundsBehavior == QQuickFlickable::StopAtBounds) {
+ if (newY <= maxY) {
+ newY = maxY;
+ rejectY = vData.pressPos == maxY && vData.move.value() == maxY && dy < 0;
+ }
+ if (newY >= minY) {
+ newY = minY;
+ rejectY = vData.pressPos == minY && vData.move.value() == minY && dy > 0;
+ }
+ } else {
+ if (newY > minY)
+ newY = minY + (newY - minY) / 2;
+ if (newY < maxY && maxY - minY <= 0)
+ newY = maxY + (newY - maxY) / 2;
}
if (!rejectY && stealMouse && dy != 0.0) {
clearTimeline();
@@ -1077,17 +1047,20 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
qreal newX = dx + hData.pressPos - hData.dragStartOffset;
const qreal minX = hData.dragMinBound + hData.startMargin;
const qreal maxX = hData.dragMaxBound - hData.endMargin;
- if (newX > minX)
- newX = minX + (newX - minX) / 2;
- if (newX < maxX && maxX - minX <= 0)
- newX = maxX + (newX - maxX) / 2;
- if (boundsBehavior == QQuickFlickable::StopAtBounds && newX <= maxX) {
- newX = maxX;
- rejectX = hData.pressPos == maxX && dx < 0;
- }
- if (boundsBehavior == QQuickFlickable::StopAtBounds && newX >= minX) {
- newX = minX;
- rejectX = hData.pressPos == minX && dx > 0;
+ if (boundsBehavior == QQuickFlickable::StopAtBounds) {
+ if (newX <= maxX) {
+ newX = maxX;
+ rejectX = hData.pressPos == maxX && hData.move.value() == maxX && dx < 0;
+ }
+ if (newX >= minX) {
+ newX = minX;
+ rejectX = hData.pressPos == minX && hData.move.value() == minX && dx > 0;
+ }
+ } else {
+ if (newX > minX)
+ newX = minX + (newX - minX) / 2;
+ if (newX < maxX && maxX - minX <= 0)
+ newX = maxX + (newX - maxX) / 2;
}
if (!rejectX && stealMouse && dx != 0.0) {
@@ -2075,12 +2048,13 @@ bool QQuickFlickable::sendMouseEvent(QQuickItem *item, QMouseEvent *event)
if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) || grabberDisabled) {
d->clearDelayedPress();
grabMouse();
+ } else if (d->delayedPressEvent) {
+ grabMouse();
}
- // Do not accept this event when filtering, as this would force the mouse grab to the child
const bool filtered = stealThisEvent || d->delayedPressEvent || grabberDisabled;
if (filtered) {
- event->setAccepted(false);
+ event->setAccepted(true);
}
return filtered;
} else if (d->lastPosTime != -1) {
diff --git a/src/quick/items/qquickflickablebehavior_p.h b/src/quick/items/qquickflickablebehavior_p.h
new file mode 100644
index 0000000000..317d6512e6
--- /dev/null
+++ b/src/quick/items/qquickflickablebehavior_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Research In Motion.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFLICKABLEBEHAVIOR_H
+#define QQUICKFLICKABLEBEHAVIOR_H
+
+/* ### Platform specific flickable mechanics are defined either here, or in
+ mkspec files. Long-term (QtQuick 3) Flickable needs to allow such
+ mechanic details to be controlled via QML so that platforms can easily
+ load custom behavior at QML compile time.
+*/
+
+// The maximum number of pixels a flick can overshoot
+#ifndef QML_FLICK_OVERSHOOT
+#define QML_FLICK_OVERSHOOT 150
+#endif
+
+// The number of samples to use in calculating the velocity of a flick
+#ifndef QML_FLICK_SAMPLEBUFFER
+#define QML_FLICK_SAMPLEBUFFER 3
+#endif
+
+// The number of samples to discard when calculating the flick velocity.
+// Touch panels often produce inaccurate results as the finger is lifted.
+#ifndef QML_FLICK_DISCARDSAMPLES
+#define QML_FLICK_DISCARDSAMPLES 0
+#endif
+
+// The default maximum velocity of a flick.
+#ifndef QML_FLICK_DEFAULTMAXVELOCITY
+#ifdef Q_OS_BLACKBERRY
+#define QML_FLICK_DEFAULTMAXVELOCITY 10000
+#else
+#define QML_FLICK_DEFAULTMAXVELOCITY 2500
+#endif
+#endif
+
+// The default deceleration of a flick.
+#ifndef QML_FLICK_DEFAULTDECELERATION
+#ifdef Q_OS_BLACKBERRY
+#define QML_FLICK_DEFAULTDECELERATION 5000
+#else
+#define QML_FLICK_DEFAULTDECELERATION 1500
+#endif
+#endif
+
+// How much faster to decelerate when overshooting
+#ifndef QML_FLICK_OVERSHOOTFRICTION
+#define QML_FLICK_OVERSHOOTFRICTION 8
+#endif
+
+// Multiflick acceleration minimum flick velocity threshold
+#ifndef QML_FLICK_MULTIFLICK_THRESHOLD
+#define QML_FLICK_MULTIFLICK_THRESHOLD 1250
+#endif
+
+// Multiflick acceleration minimum contentSize/viewSize ratio
+#ifndef QML_FLICK_MULTIFLICK_RATIO
+#define QML_FLICK_MULTIFLICK_RATIO 10
+#endif
+
+// Multiflick acceleration maximum velocity multiplier
+#ifndef QML_FLICK_MULTIFLICK_MAXBOOST
+#define QML_FLICK_MULTIFLICK_MAXBOOST 3.0
+#endif
+
+#endif //QQUICKFLICKABLEBEHAVIOR_H
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 96797a7588..d6dd7cb61a 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -6572,15 +6572,7 @@ void QQuickItem::grabMouse()
if (!d->window)
return;
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(d->window);
- if (windowPriv->mouseGrabberItem == this)
- return;
-
- QQuickItem *oldGrabber = windowPriv->mouseGrabberItem;
- windowPriv->mouseGrabberItem = this;
- if (oldGrabber) {
- QEvent ev(QEvent::UngrabMouse);
- d->window->sendEvent(oldGrabber, &ev);
- }
+ windowPriv->setMouseGrabber(this);
}
/*!
@@ -6960,7 +6952,10 @@ bool QQuickItem::event(QEvent *ev)
touchEvent(static_cast<QTouchEvent*>(ev));
break;
case QEvent::StyleAnimationUpdate:
- update();
+ if (isVisible()) {
+ ev->accept();
+ update();
+ }
break;
case QEvent::HoverEnter:
hoverEnterEvent(static_cast<QHoverEvent*>(ev));
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 3987ff0cfb..ef5c63e40f 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -451,7 +451,7 @@ public:
// dirtyToString()
TransformUpdateMask = TransformOrigin | Transform | BasicTransform | Position |
- Size | Window,
+ Window,
ComplexTransformUpdateMask = Transform | Window,
ContentUpdateMask = Size | Content | Smooth | Window | Antialiasing,
ChildrenUpdateMask = ChildrenChanged | ChildrenStackingChanged | EffectReference | Window
diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h
index 5931d6c09e..ad026a3152 100644
--- a/src/quick/items/qquickitemview_p.h
+++ b/src/quick/items/qquickitemview_p.h
@@ -334,6 +334,21 @@ public:
}
}
+ void setSections(const QString &prev, const QString &sect, const QString &next) {
+ bool prevChanged = prev != m_prevSection;
+ bool sectChanged = sect != m_section;
+ bool nextChanged = next != m_nextSection;
+ m_prevSection = prev;
+ m_section = sect;
+ m_nextSection = next;
+ if (prevChanged)
+ Q_EMIT prevSectionChanged();
+ if (sectChanged)
+ Q_EMIT sectionChanged();
+ if (nextChanged)
+ Q_EMIT nextSectionChanged();
+ }
+
void emitAdd() { Q_EMIT add(); }
void emitRemove() { Q_EMIT remove(); }
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 7f6c7fdbb9..6324d7960a 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -143,7 +143,8 @@ public:
QQuickListView::SnapMode snapMode;
QSmoothedAnimation *highlightPosAnimator;
- QSmoothedAnimation *highlightSizeAnimator;
+ QSmoothedAnimation *highlightWidthAnimator;
+ QSmoothedAnimation *highlightHeightAnimator;
qreal highlightMoveVelocity;
qreal highlightResizeVelocity;
int highlightResizeDuration;
@@ -168,7 +169,7 @@ public:
, visiblePos(0)
, averageSize(100.0), spacing(0.0)
, snapMode(QQuickListView::NoSnap)
- , highlightPosAnimator(0), highlightSizeAnimator(0)
+ , highlightPosAnimator(0), highlightWidthAnimator(0), highlightHeightAnimator(0)
, highlightMoveVelocity(400), highlightResizeVelocity(400), highlightResizeDuration(-1)
, sectionCriteria(0), currentSectionItem(0), nextSectionItem(0)
, overshootDist(0.0), correctFlick(false), inFlickCorrection(false)
@@ -177,7 +178,8 @@ public:
}
~QQuickListViewPrivate() {
delete highlightPosAnimator;
- delete highlightSizeAnimator;
+ delete highlightWidthAnimator;
+ delete highlightHeightAnimator;
}
friend class QQuickViewSection;
@@ -487,7 +489,7 @@ QString QQuickListViewPrivate::sectionAt(int modelIndex)
return item->attached->section();
QString section;
- if (sectionCriteria) {
+ if (sectionCriteria && modelIndex >= 0 && modelIndex < itemCount) {
QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
section = sectionCriteria->sectionString(propValue);
}
@@ -565,19 +567,19 @@ FxViewItem *QQuickListViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
// initialise attached properties
if (sectionCriteria) {
QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
- listItem->attached->setSection(sectionCriteria->sectionString(propValue));
+ QString section = sectionCriteria->sectionString(propValue);
+ QString prevSection;
+ QString nextSection;
if (modelIndex > 0) {
if (FxViewItem *item = itemBefore(modelIndex))
- listItem->attached->setPrevSection(item->attached->section());
+ prevSection = item->attached->section();
else
- listItem->attached->setPrevSection(sectionAt(modelIndex-1));
+ prevSection = sectionAt(modelIndex-1);
}
if (modelIndex < model->count()-1) {
- if (FxViewItem *item = visibleItem(modelIndex+1))
- listItem->attached->setNextSection(static_cast<QQuickListViewAttached*>(item->attached)->section());
- else
- listItem->attached->setNextSection(sectionAt(modelIndex+1));
+ nextSection = sectionAt(modelIndex+1);
}
+ listItem->attached->setSections(prevSection, section, nextSection);
}
return listItem;
@@ -855,9 +857,11 @@ void QQuickListViewPrivate::createHighlight()
highlight = 0;
delete highlightPosAnimator;
- delete highlightSizeAnimator;
+ delete highlightWidthAnimator;
+ delete highlightHeightAnimator;
highlightPosAnimator = 0;
- highlightSizeAnimator = 0;
+ highlightWidthAnimator = 0;
+ highlightHeightAnimator = 0;
changed = true;
}
@@ -878,11 +882,15 @@ void QQuickListViewPrivate::createHighlight()
highlightPosAnimator->velocity = highlightMoveVelocity;
highlightPosAnimator->userDuration = highlightMoveDuration;
- const QLatin1String sizeProp(orient == QQuickListView::Vertical ? "height" : "width");
- highlightSizeAnimator = new QSmoothedAnimation;
- highlightSizeAnimator->velocity = highlightResizeVelocity;
- highlightSizeAnimator->userDuration = highlightResizeDuration;
- highlightSizeAnimator->target = QQmlProperty(item, sizeProp);
+ highlightWidthAnimator = new QSmoothedAnimation;
+ highlightWidthAnimator->velocity = highlightResizeVelocity;
+ highlightWidthAnimator->userDuration = highlightResizeDuration;
+ highlightWidthAnimator->target = QQmlProperty(item, "width");
+
+ highlightHeightAnimator = new QSmoothedAnimation;
+ highlightHeightAnimator->velocity = highlightResizeVelocity;
+ highlightHeightAnimator->userDuration = highlightResizeDuration;
+ highlightHeightAnimator->target = QQmlProperty(item, "height");
highlight = newHighlight;
changed = true;
@@ -905,7 +913,8 @@ void QQuickListViewPrivate::updateHighlight()
highlightPosAnimator->to = isContentFlowReversed()
? -listItem->itemPosition()-listItem->itemSize()
: listItem->itemPosition();
- highlightSizeAnimator->to = listItem->itemSize();
+ highlightWidthAnimator->to = listItem->item->width();
+ highlightHeightAnimator->to = listItem->item->height();
if (orient == QQuickListView::Vertical) {
if (highlight->item->width() == 0)
highlight->item->setWidth(currentItem->item->width());
@@ -915,7 +924,8 @@ void QQuickListViewPrivate::updateHighlight()
}
highlightPosAnimator->restart();
- highlightSizeAnimator->restart();
+ highlightWidthAnimator->restart();
+ highlightHeightAnimator->restart();
}
updateTrackedItem();
}
@@ -1968,8 +1978,10 @@ void QQuickListView::setHighlightFollowsCurrentItem(bool autoHighlight)
if (!autoHighlight) {
if (d->highlightPosAnimator)
d->highlightPosAnimator->stop();
- if (d->highlightSizeAnimator)
- d->highlightSizeAnimator->stop();
+ if (d->highlightWidthAnimator)
+ d->highlightWidthAnimator->stop();
+ if (d->highlightHeightAnimator)
+ d->highlightHeightAnimator->stop();
}
QQuickItemView::setHighlightFollowsCurrentItem(autoHighlight);
}
@@ -2296,8 +2308,10 @@ void QQuickListView::setHighlightResizeVelocity(qreal speed)
Q_D(QQuickListView);
if (d->highlightResizeVelocity != speed) {
d->highlightResizeVelocity = speed;
- if (d->highlightSizeAnimator)
- d->highlightSizeAnimator->velocity = d->highlightResizeVelocity;
+ if (d->highlightWidthAnimator)
+ d->highlightWidthAnimator->velocity = d->highlightResizeVelocity;
+ if (d->highlightHeightAnimator)
+ d->highlightHeightAnimator->velocity = d->highlightResizeVelocity;
emit highlightResizeVelocityChanged();
}
}
@@ -2313,8 +2327,10 @@ void QQuickListView::setHighlightResizeDuration(int duration)
Q_D(QQuickListView);
if (d->highlightResizeDuration != duration) {
d->highlightResizeDuration = duration;
- if (d->highlightSizeAnimator)
- d->highlightSizeAnimator->userDuration = d->highlightResizeDuration;
+ if (d->highlightWidthAnimator)
+ d->highlightWidthAnimator->userDuration = d->highlightResizeDuration;
+ if (d->highlightHeightAnimator)
+ d->highlightHeightAnimator->userDuration = d->highlightResizeDuration;
emit highlightResizeDurationChanged();
}
}
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 7d04be2393..b83c21428c 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -106,6 +106,7 @@ void QQuickLoaderPrivate::clear()
component->deleteLater();
component = 0;
}
+ componentStrongReference.clear();
source = QUrl();
if (item) {
@@ -472,6 +473,10 @@ void QQuickLoader::setSourceComponent(QQmlComponent *comp)
d->clear();
d->component = comp;
+ if (comp) {
+ if (QQmlData *ddata = QQmlData::get(comp))
+ d->componentStrongReference = ddata->jsWrapper.value();
+ }
d->loadingFromSource = false;
if (d->active)
diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h
index 9c94b4ce38..32c271222d 100644
--- a/src/quick/items/qquickloader_p_p.h
+++ b/src/quick/items/qquickloader_p_p.h
@@ -106,6 +106,7 @@ public:
QQuickItem *item;
QObject *object;
QQmlComponent *component;
+ QV4::PersistentValue componentStrongReference; // To ensure GC doesn't delete components created by Qt.createComponent
QQmlContext *itemContext;
QQuickLoaderIncubator *incubator;
QV4::PersistentValue initialPropertyValues;
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 808c2638e2..438ec29fd0 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -822,6 +822,12 @@ void QQuickMouseArea::ungrabMouse()
d->pressed = 0;
d->stealMouse = false;
setKeepMouseGrab(false);
+
+#ifndef QT_NO_DRAGANDDROP
+ if (d->drag)
+ d->drag->setActive(false);
+#endif
+
emit canceled();
emit pressedChanged();
emit pressedButtonsChanged();
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index 1f41fe04e5..0080f54d20 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -42,6 +42,7 @@
#include "qquickpathview_p.h"
#include "qquickpathview_p_p.h"
#include "qquickwindow.h"
+#include "qquickflickablebehavior_p.h" //Contains flicking behavior defines
#include <QtQuick/private/qquickstate_p.h>
#include <private/qqmlglobal_p.h>
@@ -56,22 +57,6 @@
#include <QtCore/qmath.h>
#include <math.h>
-// The number of samples to use in calculating the velocity of a flick
-#ifndef QML_FLICK_SAMPLEBUFFER
-#define QML_FLICK_SAMPLEBUFFER 1
-#endif
-
-// The number of samples to discard when calculating the flick velocity.
-// Touch panels often produce inaccurate results as the finger is lifted.
-#ifndef QML_FLICK_DISCARDSAMPLES
-#define QML_FLICK_DISCARDSAMPLES 0
-#endif
-
-// The default maximum velocity of a flick.
-#ifndef QML_FLICK_DEFAULTMAXVELOCITY
-#define QML_FLICK_DEFAULTMAXVELOCITY 2500
-#endif
-
QT_BEGIN_NAMESPACE
diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp
index 3ab13dbbc7..a615cb6f91 100644
--- a/src/quick/items/qquickshadereffectnode.cpp
+++ b/src/quick/items/qquickshadereffectnode.cpp
@@ -146,7 +146,6 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
continue;
}
}
- qWarning("ShaderEffect: source or provider missing when binding textures");
glBindTexture(GL_TEXTURE_2D, 0);
} else if (d.specialType == UniformData::Opacity) {
program()->setUniformValue(loc, state.opacity());
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index e076a342df..98203c51e5 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -158,16 +158,24 @@ QQuickShaderEffectTexture::QQuickShaderEffectTexture(QQuickItem *shaderSource)
QQuickShaderEffectTexture::~QQuickShaderEffectTexture()
{
- if (m_renderer)
- disconnect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture()));
+ invalidated();
+}
+
+void QQuickShaderEffectTexture::invalidated()
+{
delete m_renderer;
+ m_renderer = 0;
delete m_fbo;
delete m_secondaryFbo;
+ m_fbo = m_secondaryFbo = 0;
#ifdef QSG_DEBUG_FBO_OVERLAY
delete m_debugOverlay;
+ m_debugOverlay = 0;
#endif
- if (m_transparentTexture)
+ if (m_transparentTexture) {
glDeleteTextures(1, &m_transparentTexture);
+ m_transparentTexture = 0;
+ }
}
int QQuickShaderEffectTexture::textureId() const
@@ -609,6 +617,7 @@ void QQuickShaderEffectSource::ensureTexture()
"Cannot be used outside the rendering thread");
m_texture = new QQuickShaderEffectTexture(this);
+ connect(QQuickItemPrivate::get(this)->window, SIGNAL(sceneGraphInvalidated()), m_texture, SLOT(invalidated()), Qt::DirectConnection);
connect(m_texture, SIGNAL(updateRequested()), this, SLOT(update()));
connect(m_texture, SIGNAL(scheduledUpdateCompleted()), this, SIGNAL(scheduledUpdateCompleted()));
}
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index 6218775700..efa963fe64 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -124,6 +124,7 @@ Q_SIGNALS:
public Q_SLOTS:
void markDirtyTexture();
+ void invalidated();
private:
void grab();
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 9c153febb6..beb2039924 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -296,44 +296,6 @@ qreal QQuickTextPrivate::getImplicitHeight() const
The default is true.
*/
-/*!
- \qmlproperty enumeration QtQuick::Text::renderType
-
- Override the default rendering type for this component.
-
- Supported render types are:
- \list
- \li Text.QtRendering - the default
- \li Text.NativeRendering
- \endlist
-
- Select Text.NativeRendering if you prefer text to look native on the target platform and do
- not require advanced features such as transformation of the text. Using such features in
- combination with the NativeRendering render type will lend poor and sometimes pixelated
- results.
-
- On HighDpi "retina" displays and mobile and embedded platforms, this property is ignored
- and QtRendering is always used.
-*/
-QQuickText::RenderType QQuickText::renderType() const
-{
- Q_D(const QQuickText);
- return d->renderType;
-}
-
-void QQuickText::setRenderType(QQuickText::RenderType renderType)
-{
- Q_D(QQuickText);
- if (d->renderType == renderType)
- return;
-
- d->renderType = renderType;
- emit renderTypeChanged();
-
- if (isComponentComplete())
- d->updateLayout();
-}
-
void QQuickText::q_imagesLoaded()
{
Q_D(QQuickText);
@@ -640,17 +602,6 @@ void QQuickTextLine::setY(qreal y)
m_line->setPosition(QPointF(m_line->x(), y));
}
-/*!
- \qmlmethod QtQuick::Text::doLayout()
-
- Triggers a re-layout of the displayed text.
-*/
-void QQuickText::doLayout()
-{
- Q_D(QQuickText);
- d->updateSize();
-}
-
bool QQuickTextPrivate::isLineLaidOutConnected()
{
Q_Q(QQuickText);
@@ -2683,4 +2634,53 @@ void QQuickText::hoverLeaveEvent(QHoverEvent *event)
d->processHoverEvent(event);
}
+/*!
+ \qmlproperty enumeration QtQuick::Text::renderType
+
+ Override the default rendering type for this component.
+
+ Supported render types are:
+ \list
+ \li Text.QtRendering - the default
+ \li Text.NativeRendering
+ \endlist
+
+ Select Text.NativeRendering if you prefer text to look native on the target platform and do
+ not require advanced features such as transformation of the text. Using such features in
+ combination with the NativeRendering render type will lend poor and sometimes pixelated
+ results.
+
+ On HighDpi "retina" displays and mobile and embedded platforms, this property is ignored
+ and QtRendering is always used.
+*/
+QQuickText::RenderType QQuickText::renderType() const
+{
+ Q_D(const QQuickText);
+ return d->renderType;
+}
+
+void QQuickText::setRenderType(QQuickText::RenderType renderType)
+{
+ Q_D(QQuickText);
+ if (d->renderType == renderType)
+ return;
+
+ d->renderType = renderType;
+ emit renderTypeChanged();
+
+ if (isComponentComplete())
+ d->updateLayout();
+}
+
+/*!
+ \qmlmethod QtQuick::Text::doLayout()
+
+ Triggers a re-layout of the displayed text.
+*/
+void QQuickText::doLayout()
+{
+ Q_D(QQuickText);
+ d->updateSize();
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index d4427eb47e..1dd1dfa57e 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -1679,6 +1679,7 @@ bool QQuickTextInput::event(QEvent* ev)
|| ke == QKeySequence::SelectAll
|| ke == QKeySequence::SelectEndOfDocument) {
ke->accept();
+ return true;
} else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
|| ke->modifiers() == Qt::KeypadModifier) {
if (ke->key() < Qt::Key_Escape) {
@@ -1692,6 +1693,7 @@ bool QQuickTextInput::event(QEvent* ev)
case Qt::Key_Backspace:
case Qt::Key_Left:
case Qt::Key_Right:
+ ke->accept();
return true;
default:
break;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 10906dd64c..63a3b5d820 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -600,6 +600,28 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
return false;
}
+void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
+{
+ Q_Q(QQuickWindow);
+ if (mouseGrabberItem == grabber)
+ return;
+
+ QQuickItem *oldGrabber = mouseGrabberItem;
+ mouseGrabberItem = grabber;
+
+ if (touchMouseId != -1) {
+ // update the touch item for mouse touch id to the new grabber
+ itemForTouchPointId.remove(touchMouseId);
+ if (grabber)
+ itemForTouchPointId[touchMouseId] = grabber;
+ }
+
+ if (oldGrabber) {
+ QEvent ev(QEvent::UngrabMouse);
+ q->sendEvent(oldGrabber, &ev);
+ }
+}
+
void QQuickWindowPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
{
QMatrix4x4 transformMatrix(transform);
@@ -661,6 +683,7 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ QQuickItem *currentActiveFocusItem = activeFocusItem;
QQuickItem *newActiveFocusItem = 0;
QVarLengthArray<QQuickItem *, 20> changed;
@@ -737,7 +760,8 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
q->sendEvent(newActiveFocusItem, &event);
}
- emit q->focusObjectChanged(activeFocusItem);
+ if (activeFocusItem != currentActiveFocusItem)
+ emit q->focusObjectChanged(activeFocusItem);
if (!changed.isEmpty())
notifyFocusChangesRecur(changed.data(), changed.count() - 1);
@@ -764,6 +788,7 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
return;//No focus, nothing to do.
}
+ QQuickItem *currentActiveFocusItem = activeFocusItem;
QQuickItem *oldActiveFocusItem = 0;
QQuickItem *newActiveFocusItem = 0;
@@ -820,7 +845,8 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
q->sendEvent(newActiveFocusItem, &event);
}
- emit q->focusObjectChanged(activeFocusItem);
+ if (activeFocusItem != currentActiveFocusItem)
+ emit q->focusObjectChanged(activeFocusItem);
if (!changed.isEmpty())
notifyFocusChangesRecur(changed.data(), changed.count() - 1);
@@ -1218,8 +1244,11 @@ bool QQuickWindow::event(QEvent *e)
case QEvent::TouchEnd: {
QTouchEvent *touch = static_cast<QTouchEvent*>(e);
d->translateTouchEvent(touch);
- // return in order to avoid the QWindow::event below
- return d->deliverTouchEvent(touch);
+ d->deliverTouchEvent(touch);
+ // we consume all touch events ourselves to avoid duplicate
+ // mouse delivery by QtGui mouse synthesis
+ e->accept();
+ return true;
}
break;
case QEvent::TouchCancel:
@@ -1798,7 +1827,10 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEv
// First check whether the parent wants to be a filter,
// and if the parent accepts the event we are done.
if (sendFilteredTouchEvent(item->parentItem(), item, event)) {
- event->accept();
+ // If the touch was accepted (regardless by whom or in what form),
+ // update acceptedNewPoints
+ foreach (int id, matchingNewPoints)
+ acceptedNewPoints->insert(id);
return true;
}
@@ -2303,6 +2335,8 @@ void QQuickWindowPrivate::cleanupNodesOnShutdown(QQuickItem *item)
p->groupNode = 0;
p->paintNode = 0;
+
+ p->dirty(QQuickItemPrivate::Window);
}
for (int ii = 0; ii < p->childItems.count(); ++ii)
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index c23745b5f1..418633b6ac 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -127,6 +127,7 @@ public:
QPointF lastMousePosition;
bool translateTouchToMouse(QQuickItem *item, QTouchEvent *event);
void translateTouchEvent(QTouchEvent *touchEvent);
+ void setMouseGrabber(QQuickItem *grabber);
static void transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform);
static QMouseEvent *cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos = 0);
bool deliverInitialMousePressEvent(QQuickItem *, QMouseEvent *);
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index b91edc2fd5..44a4bf3db6 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -45,12 +45,50 @@
#include <QtCore/QCoreApplication>
#include <QtQml/QQmlEngine>
+#include <private/qguiapplication_p.h>
+#include <private/qqmlengine_p.h>
+#include <qpa/qplatformintegration.h>
+
QT_BEGIN_NAMESPACE
class QQuickWindowQmlImpl : public QQuickWindow, public QQmlParserStatus
{
Q_INTERFACES(QQmlParserStatus)
Q_OBJECT
+
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
+ Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged)
+
+public:
+ QQuickWindowQmlImpl(QWindow *parent = 0)
+ : QQuickWindow(parent)
+ , m_complete(false)
+ , m_visible(isVisible())
+ , m_visibility(AutomaticVisibility)
+ {
+ connect(this, &QWindow::visibleChanged, this, &QQuickWindowQmlImpl::visibleChanged);
+ connect(this, &QWindow::visibilityChanged, this, &QQuickWindowQmlImpl::visibilityChanged);
+ }
+
+ void setVisible(bool visible) {
+ if (!m_complete)
+ m_visible = visible;
+ else
+ QQuickWindow::setVisible(visible);
+ }
+
+ void setVisibility(Visibility visibility)
+ {
+ if (!m_complete)
+ m_visibility = visibility;
+ else
+ QQuickWindow::setVisibility(visibility);
+ }
+
+Q_SIGNALS:
+ void visibleChanged(bool arg);
+ void visibilityChanged(QWindow::Visibility visibility);
+
protected:
void classBegin() {
//Give QQuickView behavior when created from QML with QQmlApplicationEngine
@@ -61,7 +99,47 @@ protected:
}
}
- void componentComplete() {}
+ void componentComplete() {
+ m_complete = true;
+
+ // We have deferred window creation until we have the full picture of what
+ // the user wanted in terms of window state, geometry, visibility, etc.
+
+ if ((m_visibility == Hidden && m_visible) || (m_visibility > AutomaticVisibility && !m_visible)) {
+ QQmlData *data = QQmlData::get(this);
+ Q_ASSERT(data && data->context);
+
+ QQmlError error;
+ error.setObject(this);
+
+ const QQmlContextData* urlContext = data->context;
+ while (urlContext && urlContext->url.isEmpty())
+ urlContext = urlContext->parent;
+ error.setUrl(urlContext ? urlContext->url : QUrl());
+
+ QString objectId = data->context->findObjectId(this);
+ if (!objectId.isEmpty())
+ error.setDescription(QCoreApplication::translate("QQuickWindowQmlImpl",
+ "Conflicting properties 'visible' and 'visibility' for Window '%1'").arg(objectId));
+ else
+ error.setDescription(QCoreApplication::translate("QQuickWindowQmlImpl",
+ "Conflicting properties 'visible' and 'visibility'"));
+
+ QQmlEnginePrivate::get(data->context->engine)->warning(error);
+ }
+
+ if (m_visibility == AutomaticVisibility) {
+ setWindowState(QGuiApplicationPrivate::platformIntegration()->defaultWindowState(flags()));
+ setVisible(m_visible);
+ } else {
+ setVisibility(m_visibility);
+ }
+ }
+
+private:
+ bool m_complete;
+ bool m_visible;
+ Visibility m_visibility;
};
void QQuickWindowModule::defineModule()
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 79b5de72c0..8ff68e20bc 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -590,15 +590,18 @@ void Element::computeBounds()
}
bounds.map(*node->matrix());
- if (!qIsFinite(bounds.tl.x))
+ if (!qIsFinite(bounds.tl.x) || bounds.tl.x == FLT_MAX)
bounds.tl.x = -FLT_MAX;
- if (!qIsFinite(bounds.tl.y))
+ if (!qIsFinite(bounds.tl.y) || bounds.tl.y == FLT_MAX)
bounds.tl.y = -FLT_MAX;
- if (!qIsFinite(bounds.br.x))
+ if (!qIsFinite(bounds.br.x) || bounds.br.x == -FLT_MAX)
bounds.br.x = FLT_MAX;
- if (!qIsFinite(bounds.br.y))
+ if (!qIsFinite(bounds.br.y) || bounds.br.y == -FLT_MAX)
bounds.br.y = FLT_MAX;
+ Q_ASSERT(bounds.tl.x <= bounds.br.x);
+ Q_ASSERT(bounds.tl.y <= bounds.br.y);
+
boundsOutsideFloatRange = bounds.isOutsideFloatRange();
}
@@ -2112,6 +2115,9 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
offset += a.tupleSize * size_of_type(a.type);
}
+ if (g->drawingMode() == GL_LINE_STRIP || g->drawingMode() == GL_LINE_LOOP || g->drawingMode() == GL_LINES)
+ glLineWidth(g->lineWidth());
+
if (g->indexCount())
glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), iOffset);
else
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index 95e111552d..5404b669a0 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -104,8 +104,6 @@ struct Rect {
tl.y = pt.y;
if (pt.y > br.y)
br.y = pt.y;
- Q_ASSERT(tl.x <= br.x);
- Q_ASSERT(tl.y <= br.y);
}
void operator |= (const Rect &r) {
@@ -117,8 +115,6 @@ struct Rect {
br.x = r.br.x;
if (r.br.y > br.y)
br.y = r.br.y;
- Q_ASSERT(tl.x <= br.x);
- Q_ASSERT(tl.y <= br.y);
}
void map(const QMatrix4x4 &m);
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
index 3c9c353bd8..df70b5c5eb 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
@@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE
//#define RENDERER_DEBUG
//#define QT_GL_NO_SCISSOR_TEST
-
+static bool qsg_sanity_check = qgetenv("QSG_SANITY_CHECK").toInt();
#ifndef QSG_NO_RENDER_TIMING
static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
@@ -243,9 +243,8 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
bindTime = frameTimer.nsecsElapsed();
#endif
-#ifndef QT_NO_DEBUG
// Sanity check that attribute registers are disabled
- {
+ if (qsg_sanity_check) {
GLint count = 0;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &count);
GLint enabled;
@@ -256,7 +255,6 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
}
}
}
-#endif
render();
#ifndef QSG_NO_RENDER_TIMING
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 52df55fa92..ac1bdb7841 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -238,6 +238,8 @@ void QSGGuiThreadRenderLoop::hide(QQuickWindow *window)
m_windows.remove(window);
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ if (gl)
+ gl->makeCurrent(window);
cd->cleanupNodesOnShutdown();
if (m_windows.size() == 0) {
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 850a463c3e..d779285a44 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -48,6 +48,7 @@
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
+#include <QtGui/QOffscreenSurface>
#include <QtQuick/QQuickWindow>
#include <private/qquickwindow_p.h>
@@ -205,12 +206,14 @@ public:
class WMTryReleaseEvent : public WMWindowEvent
{
public:
- WMTryReleaseEvent(QQuickWindow *win, bool destroy)
+ WMTryReleaseEvent(QQuickWindow *win, bool destroy, QOffscreenSurface *fallback)
: WMWindowEvent(win, WM_TryRelease)
, inDestructor(destroy)
+ , fallbackSurface(fallback)
{}
bool inDestructor;
+ QOffscreenSurface *fallbackSurface;
};
class WMExposeEvent : public WMWindowEvent
@@ -295,7 +298,7 @@ public:
delete sgrc;
}
- void invalidateOpenGL(QQuickWindow *window, bool inDestructor);
+ void invalidateOpenGL(QQuickWindow *window, bool inDestructor, QOffscreenSurface *backupSurface);
void initializeOpenGL();
bool event(QEvent *);
@@ -362,17 +365,9 @@ bool QSGRenderThread::event(QEvent *e)
case WM_Expose: {
QSG_RT_DEBUG("WM_Expose");
WMExposeEvent *se = static_cast<WMExposeEvent *>(e);
-
- pendingUpdate |= RepaintRequest;
-
Q_ASSERT(!window || window == se->window);
-
+ pendingUpdate |= RepaintRequest;
windowSize = se->size;
- if (window) {
- QSG_RT_DEBUG(" - window already added...");
- return true;
- }
-
window = se->window;
return true; }
@@ -383,7 +378,7 @@ bool QSGRenderThread::event(QEvent *e)
mutex.lock();
if (window) {
- QSG_RT_DEBUG(" - removed one...");
+ QSG_RT_DEBUG(" - removed window...");
window = 0;
}
waitCondition.wakeOne();
@@ -402,10 +397,11 @@ bool QSGRenderThread::event(QEvent *e)
case WM_TryRelease: {
QSG_RT_DEBUG("WM_TryRelease");
mutex.lock();
+ wm->m_locked = true;
WMTryReleaseEvent *wme = static_cast<WMTryReleaseEvent *>(e);
if (!window || wme->inDestructor) {
QSG_RT_DEBUG(" - setting exit flag and invalidating GL");
- invalidateOpenGL(wme->window, wme->inDestructor);
+ invalidateOpenGL(wme->window, wme->inDestructor, wme->fallbackSurface);
active = gl;
if (sleeping)
stopEventProcessing = true;
@@ -413,6 +409,7 @@ bool QSGRenderThread::event(QEvent *e)
QSG_RT_DEBUG(" - not releasing anything because we have active windows...");
}
waitCondition.wakeOne();
+ wm->m_locked = false;
mutex.unlock();
return true;
}
@@ -453,7 +450,7 @@ bool QSGRenderThread::event(QEvent *e)
return QThread::event(e);
}
-void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
+void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor, QOffscreenSurface *fallback)
{
QSG_RT_DEBUG("invalidateOpenGL()");
@@ -469,7 +466,13 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
bool wipeSG = inDestructor || !window->isPersistentSceneGraph();
bool wipeGL = inDestructor || (wipeSG && !window->isPersistentOpenGLContext());
- gl->makeCurrent(window);
+ bool current = gl->makeCurrent(fallback ? static_cast<QSurface *>(fallback) : static_cast<QSurface *>(window));
+ if (!current) {
+#ifndef QT_NO_DEBUG
+ qWarning() << "Scene Graph failed to acquire GL context during cleanup";
+#endif
+ return;
+ }
// The canvas nodes must be cleaned up regardless if we are in the destructor..
if (wipeSG) {
@@ -477,6 +480,7 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
dd->cleanupNodesOnShutdown();
} else {
QSG_RT_DEBUG(" - persistent SG, avoiding cleanup");
+ gl->doneCurrent();
return;
}
@@ -510,7 +514,6 @@ void QSGRenderThread::sync()
if (windowSize.width() > 0 && windowSize.height() > 0)
current = gl->makeCurrent(window);
if (current) {
- gl->makeCurrent(window);
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
bool hadRenderer = d->renderer != 0;
d->syncSceneGraph();
@@ -528,7 +531,6 @@ void QSGRenderThread::sync()
QSG_RT_DEBUG(" - window has bad size, waiting...");
}
- QSG_RT_DEBUG(" - window has bad size, waiting...");
waitCondition.wakeOne();
mutex.unlock();
}
@@ -690,7 +692,7 @@ QSGThreadedRenderLoop::QSGThreadedRenderLoop()
: sg(QSGContext::createDefaultContext())
, m_animation_timer(0)
{
-#if defined(QSG_RENDER_LOOP_DEBUG_BASIC) || defined (QSG_RENDER_LOOP_DEBUG_FULL)
+#if defined(QSG_RENDER_LOOP_DEBUG)
qsgrl_timer.start();
#endif
@@ -817,7 +819,6 @@ void QSGThreadedRenderLoop::show(QQuickWindow *window)
win.thread = new QSGRenderThread(this, QQuickWindowPrivate::get(window)->context);
win.timerId = 0;
win.updateDuringSync = false;
- win.gotBrokenExposeFromPlatformPlugin = false;
m_windows << win;
}
@@ -883,19 +884,6 @@ void QSGThreadedRenderLoop::exposureChanged(QQuickWindow *window)
}
}
-void QSGThreadedRenderLoop::resize(QQuickWindow *window)
-{
- Window *w = windowFor(m_windows, window);
- if (w
- && w->gotBrokenExposeFromPlatformPlugin
- && window->width() > 0 && window->height() > 0
- && w->window->geometry().intersects(w->window->screen()->availableGeometry())) {
- w->gotBrokenExposeFromPlatformPlugin = false;
- handleExposure(w);
- }
-}
-
-
/*!
Will post an event to the render thread that this window should
start to render.
@@ -909,8 +897,6 @@ void QSGThreadedRenderLoop::handleExposure(Window *w)
#ifndef QT_NO_DEBUG
qWarning("QSGThreadedRenderLoop: expose event received for window with invalid geometry.");
#endif
- w->gotBrokenExposeFromPlatformPlugin = true;
- return;
}
// Because we are going to bind a GL context to it, make sure it
@@ -994,6 +980,9 @@ void QSGThreadedRenderLoop::maybeUpdate(QQuickWindow *window)
*/
void QSGThreadedRenderLoop::maybeUpdate(Window *w)
{
+ if (!QCoreApplication::instance())
+ return;
+
Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || m_locked,
"QQuickItem::update()",
"Function can only be called from GUI thread or during QQuickItem::updatePaintNode()");
@@ -1052,9 +1041,26 @@ void QSGThreadedRenderLoop::releaseResources(QQuickWindow *window, bool inDestru
w->thread->mutex.lock();
if (w->thread->isRunning() && w->thread->active) {
+
+ // The platform window might have been destroyed before
+ // hide/release/windowDestroyed is called, so we need to have a
+ // fallback surface to perform the cleanup of the scene graph
+ // and the OpenGL resources.
+ // QOffscreenSurface must be created on the GUI thread, so we
+ // create it here and pass it on to QSGRenderThread::invalidateGL()
+ QOffscreenSurface *fallback = 0;
+ if (!window->handle()) {
+ QSG_GUI_DEBUG(w->window, " - using fallback surface");
+ fallback = new QOffscreenSurface();
+ fallback->setFormat(window->requestedFormat());
+ fallback->create();
+ }
+
QSG_GUI_DEBUG(w->window, " - posting release request to render thread");
- w->thread->postEvent(new WMTryReleaseEvent(window, inDestructor));
+ w->thread->postEvent(new WMTryReleaseEvent(window, inDestructor, fallback));
w->thread->waitCondition.wait(&w->thread->mutex);
+
+ delete fallback;
}
w->thread->mutex.unlock();
}
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
index 844d180788..5943d0bd08 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h
+++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
@@ -60,7 +60,6 @@ public:
void show(QQuickWindow *window);
void hide(QQuickWindow *window);
- void resize(QQuickWindow *window);
void windowDestroyed(QQuickWindow *window);
void exposureChanged(QQuickWindow *window);
@@ -90,7 +89,6 @@ private:
QSGRenderThread *thread;
int timerId;
uint updateDuringSync : 1;
- uint gotBrokenExposeFromPlatformPlugin : 1;
};
friend class QSGRenderThread;
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 0c128d5cae..0b6d42aca6 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -240,7 +240,11 @@ void QSGWindowsRenderLoop::hide(QQuickWindow *window)
if (window->isExposed())
handleObscurity();
+ if (!m_gl)
+ return;
+
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ m_gl->makeCurrent(window);
cd->cleanupNodesOnShutdown();
// If this is the last tracked window, check for persistent SG and GL and
diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp
index 8678d106ff..75bf0b6e3c 100644
--- a/src/quick/scenegraph/util/qsgatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgatlastexture.cpp
@@ -448,6 +448,7 @@ QSGTexture *Texture::removedFromAtlas() const
if (!m_nonatlas_texture) {
m_nonatlas_texture = new QSGPlainTexture();
m_nonatlas_texture->setImage(m_image);
+ m_nonatlas_texture->setFiltering(filtering());
}
return m_nonatlas_texture;
}
diff --git a/src/quick/util/qquickapplication.cpp b/src/quick/util/qquickapplication.cpp
index 244e13888c..fb7c900252 100644
--- a/src/quick/util/qquickapplication.cpp
+++ b/src/quick/util/qquickapplication.cpp
@@ -123,7 +123,7 @@ bool QQuickApplication::eventFilter(QObject *, QEvent *event)
if (d->isActive != wasActive) {
emit activeChanged();
}
- } else if (event->type() == QEvent::LayoutDirectionChange) {
+ } else if (event->type() == QEvent::ApplicationLayoutDirectionChange) {
Qt::LayoutDirection newDirection = QGuiApplication::layoutDirection();
if (d->direction != newDirection) {
d->direction = newDirection;
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 26258fdc5f..055d6b7e29 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -519,6 +519,9 @@ void QQuickPixmapReader::processJobs()
runningJob->loading = true;
QUrl url = runningJob->url;
+ QQmlPixmapProfiler pixmapProfiler;
+ pixmapProfiler.startLoading(url);
+
QSize requestSize = runningJob->requestSize;
locker.unlock();
processJob(runningJob, url, requestSize);
@@ -897,8 +900,7 @@ bool QQuickPixmapReply::event(QEvent *event)
pixmapProfiler.finishLoading(data->url);
data->textureFactory = de->textureFactory;
data->implicitSize = de->implicitSize;
- if (data->implicitSize.width() > 0)
- pixmapProfiler.setSize(url, data->implicitSize.width(), data->implicitSize.height());
+ pixmapProfiler.setSize(url, data->requestSize.width() > 0 ? data->requestSize : data->implicitSize);
} else {
pixmapProfiler.errorLoading(data->url);
data->errorString = de->errorString;
@@ -968,8 +970,6 @@ void QQuickPixmapData::addToCache()
inCache = true;
QQmlPixmapProfiler pixmapProfiler;
pixmapProfiler.cacheCountChanged(url, pixmapStore()->m_cache.count());
- if (implicitSize.width() > 0)
- pixmapProfiler.setSize(url, implicitSize.width(), implicitSize.height());
}
}
@@ -1033,17 +1033,6 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
if (localFile.isEmpty())
return 0;
- // check for "retina" high-dpi and use @2x file if it exixts
- if (qApp->devicePixelRatio() > 1) {
- const int dotIndex = localFile.lastIndexOf(QLatin1Char('.'));
- if (dotIndex != -1) {
- QString retinaFile = localFile;
- retinaFile.insert(dotIndex, QStringLiteral("@2x"));
- if (QFile(retinaFile).exists())
- localFile = retinaFile;
- }
- }
-
QFile f(localFile);
QSize readSize;
QString errorString;
@@ -1256,8 +1245,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
d = createPixmapDataSync(this, engine, url, requestSize, &ok);
if (ok) {
pixmapProfiler.finishLoading(url);
- if (d->implicitSize.width() > 0)
- QQmlPixmapProfiler().setSize(url, d->implicitSize.width(), d->implicitSize.height());
+ pixmapProfiler.setSize(url, d->requestSize.width() > 0 ? d->requestSize : d->implicitSize);
if (options & QQuickPixmap::Cache)
d->addToCache();
return;