summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2010-09-23 07:25:18 (GMT)
committerQt Continuous Integration System <qt-info@nokia.com>2010-09-23 07:25:18 (GMT)
commit932e67e3e817f0e2625ff60594e6e536920a329a (patch)
treec63afe16124bb3af2429b7cf04afaa65760ad600
parent979ab9bf9394210dc4812082fe40b083155447c5 (diff)
parent4f24b2fbe7fbbdae95b27381e258ec7b665445c5 (diff)
downloadQt-932e67e3e817f0e2625ff60594e6e536920a329a.zip
Qt-932e67e3e817f0e2625ff60594e6e536920a329a.tar.gz
Qt-932e67e3e817f0e2625ff60594e6e536920a329a.tar.bz2
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/oslo-staging-2 into 4.7-integration
* '4.7' of scm.dev.nokia.troll.no:qt/oslo-staging-2: QPainter not restored correctly in Graphics View. Setting QGraphicsItem::ItemClipsChildrenToShape forces ItemClipsToShape Fix compilation Fixed drawing of QPixmaps with masks in the GL 2 and X11 engines. Fix warning on MSVC QThread: make sure start works even if called after exit Revert "Fixed painter path drawing on FBO without stencil buffer." Fix a crash with D&d on mingw Revert "Keep other text format with QTextOption::SuppressColors tag on" Fixed stencil buffer on FBOs with OpenGL ES. Keep other text format with QTextOption::SuppressColors tag on QTreeView: do not scroll to top if last item is removed
-rw-r--r--src/corelib/thread/qthread_unix.cpp2
-rw-r--r--src/corelib/thread/qthread_win.cpp2
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp126
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp3
-rw-r--r--src/gui/image/qpixmap_x11.cpp11
-rw-r--r--src/gui/image/qpixmap_x11_p.h1
-rw-r--r--src/gui/image/qpixmapdata.cpp5
-rw-r--r--src/gui/image/qpixmapdata_p.h1
-rw-r--r--src/gui/itemviews/qtreeview.cpp4
-rw-r--r--src/gui/kernel/qdnd_win.cpp12
-rw-r--r--src/gui/styles/qstylehelper_p.h2
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp28
-rw-r--r--src/opengl/qgl_x11.cpp4
-rw-r--r--src/opengl/qglframebufferobject.cpp105
-rw-r--r--src/opengl/qglframebufferobject_p.h5
-rw-r--r--tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp188
-rw-r--r--tests/auto/qgraphicsview/tst_qgraphicsview.cpp48
-rw-r--r--tests/auto/qthread/tst_qthread.cpp41
-rw-r--r--tests/auto/qtreeview/tst_qtreeview.cpp22
19 files changed, 493 insertions, 117 deletions
diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp
index 2824e15..a7601b6 100644
--- a/src/corelib/thread/qthread_unix.cpp
+++ b/src/corelib/thread/qthread_unix.cpp
@@ -514,6 +514,8 @@ void QThread::start(Priority priority)
d->running = true;
d->finished = false;
d->terminated = false;
+ d->returnCode = 0;
+ d->exited = false;
pthread_attr_t attr;
pthread_attr_init(&attr);
diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp
index 37d5b87..f0cbe8d 100644
--- a/src/corelib/thread/qthread_win.cpp
+++ b/src/corelib/thread/qthread_win.cpp
@@ -405,6 +405,8 @@ void QThread::start(Priority priority)
d->running = true;
d->finished = false;
d->terminated = false;
+ d->exited = false;
+ d->returnCode = 0;
/*
NOTE: we create the thread in the suspended state, set the
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 54fdf3f..8dc15bf 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -4814,6 +4814,27 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
}
}
+static inline void setClip(QPainter *painter, QGraphicsItem *item)
+{
+ painter->save();
+ QRectF clipRect;
+ const QPainterPath clipPath(item->shape());
+ if (QPathClipper::pathToRect(clipPath, &clipRect))
+ painter->setClipRect(clipRect, Qt::IntersectClip);
+ else
+ painter->setClipPath(clipPath, Qt::IntersectClip);
+}
+
+static inline void setWorldTransform(QPainter *painter, const QTransform *const transformPtr,
+ const QTransform *effectTransform)
+{
+ Q_ASSERT(transformPtr);
+ if (effectTransform)
+ painter->setWorldTransform(*transformPtr * *effectTransform);
+ else
+ painter->setWorldTransform(*transformPtr);
+}
+
void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform,
const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget,
qreal opacity, const QTransform *effectTransform,
@@ -4822,36 +4843,37 @@ void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const Q
const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity);
const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
const bool itemHasChildren = !item->d_ptr->children.isEmpty();
+ bool setChildClip = itemClipsChildrenToShape;
+ bool itemHasChildrenStackedBehind = false;
int i = 0;
if (itemHasChildren) {
+ if (itemClipsChildrenToShape)
+ setWorldTransform(painter, transformPtr, effectTransform);
+
item->d_ptr->ensureSortedChildren();
+ // Items with the 'ItemStacksBehindParent' flag are put in front of the list
+ // so all we have to do is to check the first item.
+ itemHasChildrenStackedBehind = (item->d_ptr->children.at(0)->d_ptr->flags
+ & QGraphicsItem::ItemStacksBehindParent);
- if (itemClipsChildrenToShape) {
- painter->save();
- Q_ASSERT(transformPtr);
- if (effectTransform)
- painter->setWorldTransform(*transformPtr * *effectTransform);
- else
- painter->setWorldTransform(*transformPtr);
- QRectF clipRect;
- const QPainterPath clipPath(item->shape());
- if (QPathClipper::pathToRect(clipPath, &clipRect))
- painter->setClipRect(clipRect, Qt::IntersectClip);
- else
- painter->setClipPath(clipPath, Qt::IntersectClip);
- }
+ if (itemHasChildrenStackedBehind) {
+ if (itemClipsChildrenToShape) {
+ setClip(painter, item);
+ setChildClip = false;
+ }
- // Draw children behind
- for (i = 0; i < item->d_ptr->children.size(); ++i) {
- QGraphicsItem *child = item->d_ptr->children.at(i);
- if (wasDirtyParentSceneTransform)
- child->d_ptr->dirtySceneTransform = 1;
- if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
- break;
- if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
- continue;
- drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
+ // Draw children behind
+ for (i = 0; i < item->d_ptr->children.size(); ++i) {
+ QGraphicsItem *child = item->d_ptr->children.at(i);
+ if (wasDirtyParentSceneTransform)
+ child->d_ptr->dirtySceneTransform = 1;
+ if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
+ break;
+ if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
+ continue;
+ drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
+ }
}
}
@@ -4864,38 +4886,50 @@ void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const Q
? *exposedRegion : QRegion(), exposedRegion == 0);
const bool itemClipsToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsToShape;
- const bool savePainter = itemClipsToShape || painterStateProtection;
- if (savePainter)
- painter->save();
+ bool restorePainterClip = false;
if (!itemHasChildren || !itemClipsChildrenToShape) {
- if (effectTransform)
- painter->setWorldTransform(*transformPtr * *effectTransform);
- else
- painter->setWorldTransform(*transformPtr);
+ // Item does not have children or clip children to shape.
+ setWorldTransform(painter, transformPtr, effectTransform);
+ if ((restorePainterClip = itemClipsToShape))
+ setClip(painter, item);
+ } else if (itemHasChildrenStackedBehind){
+ // Item clips children to shape and has children stacked behind, which means
+ // the painter is already clipped to the item's shape.
+ if (itemClipsToShape) {
+ // The clip is already correct. Ensure correct world transform.
+ setWorldTransform(painter, transformPtr, effectTransform);
+ } else {
+ // Remove clip (this also ensures correct world transform).
+ painter->restore();
+ setChildClip = true;
+ }
+ } else if (itemClipsToShape) {
+ // Item clips children and itself to shape. It does not have hildren stacked
+ // behind, which means the clip has not yet been set. We set it now and re-use it
+ // for the children.
+ setClip(painter, item);
+ setChildClip = false;
}
- if (itemClipsToShape) {
- QRectF clipRect;
- const QPainterPath clipPath(item->shape());
- if (QPathClipper::pathToRect(clipPath, &clipRect))
- painter->setClipRect(clipRect, Qt::IntersectClip);
- else
- painter->setClipPath(clipPath, Qt::IntersectClip);
- }
- painter->setOpacity(opacity);
+ if (painterStateProtection && !restorePainterClip)
+ painter->save();
+ painter->setOpacity(opacity);
if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget)
item->paint(painter, &styleOptionTmp, widget);
else
drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection);
- if (savePainter)
+ if (painterStateProtection || restorePainterClip)
painter->restore();
}
// Draw children in front
if (itemHasChildren) {
+ if (setChildClip)
+ setClip(painter, item);
+
for (; i < item->d_ptr->children.size(); ++i) {
QGraphicsItem *child = item->d_ptr->children.at(i);
if (wasDirtyParentSceneTransform)
@@ -4904,11 +4938,11 @@ void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const Q
continue;
drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
}
- }
- // Restore child clip
- if (itemHasChildren && itemClipsChildrenToShape)
- painter->restore();
+ // Restore child clip
+ if (itemClipsChildrenToShape)
+ painter->restore();
+ }
}
void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren,
@@ -5271,6 +5305,7 @@ void QGraphicsScene::drawItems(QPainter *painter,
if (!d->unpolishedItems.isEmpty())
d->_q_polishItems();
+ const qreal opacity = painter->opacity();
QTransform viewTransform = painter->worldTransform();
Q_UNUSED(options);
@@ -5304,6 +5339,7 @@ void QGraphicsScene::drawItems(QPainter *painter,
topLevelItems.at(i)->d_ptr->itemDiscovered = 0;
painter->setWorldTransform(viewTransform);
+ painter->setOpacity(opacity);
}
/*!
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index c8aca80..a566c8e 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -3475,7 +3475,8 @@ void QGraphicsView::paintEvent(QPaintEvent *event)
// IndirectPainting (the else branch), because in that case we always save()
// and restore() in QGraphicsScene::drawItems().
if (!d->scene->d_func()->painterStateProtection)
- painter.setWorldTransform(viewTransform);
+ painter.setOpacity(1.0);
+ painter.setWorldTransform(viewTransform);
} else {
// Make sure we don't have unpolished items before we draw
if (!d->scene->d_func()->unpolishedItems.isEmpty())
diff --git a/src/gui/image/qpixmap_x11.cpp b/src/gui/image/qpixmap_x11.cpp
index 3d9c363..32676ba 100644
--- a/src/gui/image/qpixmap_x11.cpp
+++ b/src/gui/image/qpixmap_x11.cpp
@@ -1321,6 +1321,15 @@ QBitmap QX11PixmapData::mask() const
return mask;
}
+bool QX11PixmapData::hasMask() const
+{
+ return
+#ifndef QT_NO_XRENDER
+ (picture && d == 32) ||
+#endif
+ (d == 1) || x11_mask;
+}
+
/*!
Sets a mask bitmap.
@@ -1549,7 +1558,7 @@ QImage QX11PixmapData::toImage(const QRect &rect) const
if (!xiWrapper.xi)
return QImage();
- if (canTakeQImageFromXImage(xiWrapper))
+ if (!x11_mask && canTakeQImageFromXImage(xiWrapper))
return takeQImageFromXImage(xiWrapper);
QImage image = toImage(xiWrapper, rect);
diff --git a/src/gui/image/qpixmap_x11_p.h b/src/gui/image/qpixmap_x11_p.h
index 821fb69..fcad1a2 100644
--- a/src/gui/image/qpixmap_x11_p.h
+++ b/src/gui/image/qpixmap_x11_p.h
@@ -82,6 +82,7 @@ public:
void fill(const QColor &color);
QBitmap mask() const;
+ bool hasMask() const;
void setMask(const QBitmap &mask);
bool hasAlphaChannel() const;
void setAlphaChannel(const QPixmap &alphaChannel);
diff --git a/src/gui/image/qpixmapdata.cpp b/src/gui/image/qpixmapdata.cpp
index ef1f6c4..2813ed1 100644
--- a/src/gui/image/qpixmapdata.cpp
+++ b/src/gui/image/qpixmapdata.cpp
@@ -239,6 +239,11 @@ QBitmap QPixmapData::mask() const
return QBitmap::fromImage(mask);
}
+bool QPixmapData::hasMask() const
+{
+ return hasAlphaChannel();
+}
+
QPixmap QPixmapData::transformed(const QTransform &matrix,
Qt::TransformationMode mode) const
{
diff --git a/src/gui/image/qpixmapdata_p.h b/src/gui/image/qpixmapdata_p.h
index ec62b0b..c341930 100644
--- a/src/gui/image/qpixmapdata_p.h
+++ b/src/gui/image/qpixmapdata_p.h
@@ -99,6 +99,7 @@ public:
virtual int metric(QPaintDevice::PaintDeviceMetric metric) const = 0;
virtual void fill(const QColor &color) = 0;
virtual QBitmap mask() const;
+ virtual bool hasMask() const;
virtual void setMask(const QBitmap &mask);
virtual bool hasAlphaChannel() const = 0;
virtual QPixmap transformed(const QTransform &matrix,
diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp
index b797776..40b51fe 100644
--- a/src/gui/itemviews/qtreeview.cpp
+++ b/src/gui/itemviews/qtreeview.cpp
@@ -3435,6 +3435,10 @@ void QTreeViewPrivate::updateScrollBars()
if (!viewportSize.isValid())
viewportSize = QSize(0, 0);
+ if (viewItems.isEmpty()) {
+ q->doItemsLayout();
+ }
+
int itemsInViewport = 0;
if (uniformRowHeights) {
if (defaultItemHeight <= 0)
diff --git a/src/gui/kernel/qdnd_win.cpp b/src/gui/kernel/qdnd_win.cpp
index a164c2a..7083886 100644
--- a/src/gui/kernel/qdnd_win.cpp
+++ b/src/gui/kernel/qdnd_win.cpp
@@ -515,7 +515,7 @@ static inline Qt::MouseButtons keystate_to_mousebutton(DWORD grfKeyState)
//---------------------------------------------------------------------
// IDropSource Methods
//---------------------------------------------------------------------
-STDMETHODIMP
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
QOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
{
#ifdef QDND_DEBUG
@@ -545,7 +545,7 @@ QOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
}
}
-STDMETHODIMP
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
QOleDropSource::GiveFeedback(DWORD dwEffect)
{
Qt::DropAction action = translateToQDragDropAction(dwEffect);
@@ -626,7 +626,7 @@ QOleDropTarget::Release(void)
// IDropTarget Methods
//---------------------------------------------------------------------
-STDMETHODIMP
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
QOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
{
#ifdef QDND_DEBUG
@@ -688,7 +688,7 @@ void QOleDropTarget::sendDragEnterEvent(QWidget *dragEnterWidget, DWORD grfKeySt
}
-STDMETHODIMP
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
QOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
{
#ifdef QDND_DEBUG
@@ -758,7 +758,7 @@ QOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
return NOERROR;
}
-STDMETHODIMP
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
QOleDropTarget::DragLeave()
{
#ifdef QDND_DEBUG
@@ -785,7 +785,7 @@ QOleDropTarget::DragLeave()
#define KEY_STATE_BUTTON_MASK (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)
-STDMETHODIMP
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
QOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
{
#ifdef QDND_DEBUG
diff --git a/src/gui/styles/qstylehelper_p.h b/src/gui/styles/qstylehelper_p.h
index 71fce55..3759929 100644
--- a/src/gui/styles/qstylehelper_p.h
+++ b/src/gui/styles/qstylehelper_p.h
@@ -108,7 +108,7 @@ template <typename T>
{
typedef HexString<T> type;
enum { ExactSize = true };
- static int size(const HexString<T> &str) { return sizeof(str.val) * 2; }
+ static int size(const HexString<T> &) { return sizeof(T) * 2; }
static inline void appendTo(const HexString<T> &str, QChar *&out) { str.write(out); }
};
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 2347e66..6eb5a36 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -866,32 +866,6 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
if (do_vectorpath_cache)
path.makeCacheable();
- if (!device->format().stencil()) {
- // If there is no stencil buffer, triangulate the path instead.
-
- QRectF bbox = path.controlPointRect();
- // If the path doesn't fit within these limits, it is possible that the triangulation will fail.
- bool withinLimits = (bbox.left() > -0x8000 * inverseScale)
- && (bbox.right() < 0x8000 * inverseScale)
- && (bbox.top() > -0x8000 * inverseScale)
- && (bbox.bottom() < 0x8000 * inverseScale);
- if (withinLimits) {
- QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale));
-
- QVarLengthArray<float> vertices(polys.vertices.size());
- for (int i = 0; i < polys.vertices.size(); ++i)
- vertices[i] = float(inverseScale * polys.vertices.at(i));
-
- prepareForDraw(currentBrush.isOpaque());
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, vertices.constData());
- glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_INT, polys.indices.constData());
- } else {
- // We can't handle big, concave painter paths with OpenGL without stencil buffer.
- qWarning("Painter path exceeds +/-32767 pixels.");
- }
- return;
- }
-
// The path is too complicated & needs the stencil technique
vertexCoordinateArray.clear();
vertexCoordinateArray.addPath(path, inverseScale, false);
@@ -1340,7 +1314,7 @@ void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, c
QGLRect srcRect(src.left(), top, src.right(), bottom);
bool isBitmap = pixmap.isQBitmap();
- bool isOpaque = !isBitmap && !pixmap.hasAlphaChannel();
+ bool isOpaque = !isBitmap && !pixmap.hasAlphaChannel() && !pixmap.pixmapData()->hasMask();
d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp
index f3a4c95..7f4c670 100644
--- a/src/opengl/qgl_x11.cpp
+++ b/src/opengl/qgl_x11.cpp
@@ -1776,6 +1776,10 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, cons
QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pixmap->data_ptr().data());
Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class);
+ // We can't use TFP if the pixmap has a separate X11 mask
+ if (pixmapData->x11_mask)
+ return 0;
+
if (!qt_resolveTextureFromPixmap(paintDevice))
return 0;
diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp
index adbba85..6c9b288 100644
--- a/src/opengl/qglframebufferobject.cpp
+++ b/src/opengl/qglframebufferobject.cpp
@@ -324,10 +324,6 @@ void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f,
fboFormat.setStencil(true);
} else if (attachment == QGLFramebufferObject::Depth) {
fboFormat.setDepth(true);
- fboFormat.setStencil(false);
- } else {
- fboFormat.setDepth(false);
- fboFormat.setStencil(false);
}
GLenum format = f->format().internalTextureFormat();
@@ -472,13 +468,17 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &samples);
}
+ // In practice, a combined depth-stencil buffer is supported by all desktop platforms, while a
+ // separate stencil buffer is not. On embedded devices however, a combined depth-stencil buffer
+ // might not be supported while separate buffers are, according to QTBUG-12861.
+
if (attachment == QGLFramebufferObject::CombinedDepthStencil
&& (QGLExtensions::glExtensions() & QGLExtensions::PackedDepthStencil)) {
// depth and stencil buffer needs another extension
- glGenRenderbuffers(1, &depth_stencil_buffer);
- Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer));
- glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
- Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer));
+ glGenRenderbuffers(1, &depth_buffer);
+ Q_ASSERT(!glIsRenderbuffer(depth_buffer));
+ glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_buffer);
+ Q_ASSERT(glIsRenderbuffer(depth_buffer));
if (samples != 0 && glRenderbufferStorageMultisampleEXT)
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
@@ -486,24 +486,26 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
glRenderbufferStorage(GL_RENDERBUFFER_EXT,
GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
- GLint i = 0;
- glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
+ stencil_buffer = depth_buffer;
glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
- GL_RENDERBUFFER_EXT, depth_stencil_buffer);
+ GL_RENDERBUFFER_EXT, depth_buffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
- GL_RENDERBUFFER_EXT, depth_stencil_buffer);
- fbo_attachment = QGLFramebufferObject::CombinedDepthStencil;
+ GL_RENDERBUFFER_EXT, stencil_buffer);
valid = checkFramebufferStatus();
- if (!valid)
- glDeleteRenderbuffers(1, &depth_stencil_buffer);
- } else if (attachment == QGLFramebufferObject::Depth
- || attachment == QGLFramebufferObject::CombinedDepthStencil)
+ if (!valid) {
+ glDeleteRenderbuffers(1, &depth_buffer);
+ stencil_buffer = depth_buffer = 0;
+ }
+ }
+
+ if (depth_buffer == 0 && (attachment == QGLFramebufferObject::CombinedDepthStencil
+ || (attachment == QGLFramebufferObject::Depth)))
{
- glGenRenderbuffers(1, &depth_stencil_buffer);
- Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer));
- glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
- Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer));
+ glGenRenderbuffers(1, &depth_buffer);
+ Q_ASSERT(!glIsRenderbuffer(depth_buffer));
+ glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_buffer);
+ Q_ASSERT(glIsRenderbuffer(depth_buffer));
if (samples != 0 && glRenderbufferStorageMultisampleEXT) {
#ifdef QT_OPENGL_ES
#define GL_DEPTH_COMPONENT16 0x81A5
@@ -521,14 +523,53 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height());
#endif
}
- GLint i = 0;
- glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
- GL_RENDERBUFFER_EXT, depth_stencil_buffer);
- fbo_attachment = QGLFramebufferObject::Depth;
+ GL_RENDERBUFFER_EXT, depth_buffer);
valid = checkFramebufferStatus();
- if (!valid)
- glDeleteRenderbuffers(1, &depth_stencil_buffer);
+ if (!valid) {
+ glDeleteRenderbuffers(1, &depth_buffer);
+ depth_buffer = 0;
+ }
+ }
+
+ if (stencil_buffer == 0 && (attachment == QGLFramebufferObject::CombinedDepthStencil)) {
+ glGenRenderbuffers(1, &stencil_buffer);
+ Q_ASSERT(!glIsRenderbuffer(stencil_buffer));
+ glBindRenderbuffer(GL_RENDERBUFFER_EXT, stencil_buffer);
+ Q_ASSERT(glIsRenderbuffer(stencil_buffer));
+ if (samples != 0 && glRenderbufferStorageMultisampleEXT) {
+#ifdef QT_OPENGL_ES
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
+ GL_STENCIL_INDEX8_EXT, size.width(), size.height());
+#else
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
+ GL_STENCIL_INDEX, size.width(), size.height());
+#endif
+ } else {
+#ifdef QT_OPENGL_ES
+ glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT,
+ size.width(), size.height());
+#else
+ glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX,
+ size.width(), size.height());
+#endif
+ }
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, stencil_buffer);
+ valid = checkFramebufferStatus();
+ if (!valid) {
+ glDeleteRenderbuffers(1, &stencil_buffer);
+ stencil_buffer = 0;
+ }
+ }
+
+ // The FBO might have become valid after removing the depth or stencil buffer.
+ valid = checkFramebufferStatus();
+
+ if (depth_buffer && stencil_buffer) {
+ fbo_attachment = QGLFramebufferObject::CombinedDepthStencil;
+ } else if (depth_buffer) {
+ fbo_attachment = QGLFramebufferObject::Depth;
} else {
fbo_attachment = QGLFramebufferObject::NoAttachment;
}
@@ -539,6 +580,10 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
glDeleteRenderbuffers(1, &color_buffer);
else
glDeleteTextures(1, &texture);
+ if (depth_buffer)
+ glDeleteRenderbuffers(1, &depth_buffer);
+ if (stencil_buffer && depth_buffer != stencil_buffer)
+ glDeleteRenderbuffers(1, &stencil_buffer);
glDeleteFramebuffers(1, &fbo);
fbo_guard.setId(0);
}
@@ -821,8 +866,10 @@ QGLFramebufferObject::~QGLFramebufferObject()
glDeleteTextures(1, &d->texture);
if (d->color_buffer)
glDeleteRenderbuffers(1, &d->color_buffer);
- if (d->depth_stencil_buffer)
- glDeleteRenderbuffers(1, &d->depth_stencil_buffer);
+ if (d->depth_buffer)
+ glDeleteRenderbuffers(1, &d->depth_buffer);
+ if (d->stencil_buffer && d->stencil_buffer != d->depth_buffer)
+ glDeleteRenderbuffers(1, &d->stencil_buffer);
GLuint fbo = d->fbo();
glDeleteFramebuffers(1, &fbo);
}
diff --git a/src/opengl/qglframebufferobject_p.h b/src/opengl/qglframebufferobject_p.h
index d8ff012..58b4e9e 100644
--- a/src/opengl/qglframebufferobject_p.h
+++ b/src/opengl/qglframebufferobject_p.h
@@ -126,7 +126,7 @@ private:
class QGLFramebufferObjectPrivate
{
public:
- QGLFramebufferObjectPrivate() : fbo_guard(0), texture(0), depth_stencil_buffer(0)
+ QGLFramebufferObjectPrivate() : fbo_guard(0), texture(0), depth_buffer(0), stencil_buffer(0)
, color_buffer(0), valid(false), engine(0) {}
~QGLFramebufferObjectPrivate() {}
@@ -136,7 +136,8 @@ public:
bool checkFramebufferStatus() const;
QGLSharedResourceGuard fbo_guard;
GLuint texture;
- GLuint depth_stencil_buffer;
+ GLuint depth_buffer;
+ GLuint stencil_buffer;
GLuint color_buffer;
GLenum target;
QSize size;
diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
index 4476084..25ec040 100644
--- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
+++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
@@ -377,6 +377,7 @@ private slots:
void itemClipsChildrenToShape2();
void itemClipsChildrenToShape3();
void itemClipsChildrenToShape4();
+ void itemClipsChildrenToShape5();
void itemClipsTextChildToShape();
void itemClippingDiscovery();
void ancestorFlags();
@@ -5464,6 +5465,193 @@ void tst_QGraphicsItem::itemClipsChildrenToShape4()
QTRY_COMPARE(innerWidget->painted, true);
}
+//#define DEBUG_ITEM_CLIPS_CHILDREN_TO_SHAPE_5
+static inline void renderSceneToImage(QGraphicsScene *scene, QImage *image, const QString &filename)
+{
+ image->fill(0);
+ QPainter painter(image);
+ scene->render(&painter);
+ painter.end();
+#ifdef DEBUG_ITEM_CLIPS_CHILDREN_TO_SHAPE_5
+ image->save(filename);
+#else
+ Q_UNUSED(filename);
+#endif
+}
+
+void tst_QGraphicsItem::itemClipsChildrenToShape5()
+{
+ class ParentItem : public QGraphicsRectItem
+ {
+ public:
+ ParentItem(qreal x, qreal y, qreal width, qreal height)
+ : QGraphicsRectItem(x, y, width, height) {}
+
+ QPainterPath shape() const
+ {
+ QPainterPath path;
+ path.addRect(50, 50, 200, 200);
+ return path;
+ }
+ };
+
+ ParentItem *parent = new ParentItem(0, 0, 300, 300);
+ parent->setBrush(Qt::blue);
+ parent->setOpacity(0.5);
+
+ const QRegion parentRegion(0, 0, 300, 300);
+ const QRegion clippedParentRegion = parentRegion & QRect(50, 50, 200, 200);
+ QRegion childRegion;
+ QRegion grandChildRegion;
+
+ QGraphicsRectItem *topLeftChild = new QGraphicsRectItem(0, 0, 100, 100);
+ topLeftChild->setBrush(Qt::red);
+ topLeftChild->setParentItem(parent);
+ childRegion += QRect(0, 0, 100, 100);
+
+ QGraphicsRectItem *topRightChild = new QGraphicsRectItem(0, 0, 100, 100);
+ topRightChild->setBrush(Qt::red);
+ topRightChild->setParentItem(parent);
+ topRightChild->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+ topRightChild->setPos(200, 0);
+ childRegion += QRect(200, 0, 100, 100);
+
+ QGraphicsRectItem *topRightGrandChild = new QGraphicsRectItem(0, 0, 100, 100);
+ topRightGrandChild->setBrush(Qt::green);
+ topRightGrandChild->setParentItem(topRightChild);
+ topRightGrandChild->setPos(-40, 40);
+ grandChildRegion += QRect(200 - 40, 0 + 40, 100, 100) & QRect(200, 0, 100, 100);
+
+ QGraphicsRectItem *bottomLeftChild = new QGraphicsRectItem(0, 0, 100, 100);
+ bottomLeftChild->setBrush(Qt::red);
+ bottomLeftChild->setParentItem(parent);
+ bottomLeftChild->setFlag(QGraphicsItem::ItemClipsToShape);
+ bottomLeftChild->setPos(0, 200);
+ childRegion += QRect(0, 200, 100, 100);
+
+ QGraphicsRectItem *bottomLeftGrandChild = new QGraphicsRectItem(0, 0, 160, 160);
+ bottomLeftGrandChild->setBrush(Qt::green);
+ bottomLeftGrandChild->setParentItem(bottomLeftChild);
+ bottomLeftGrandChild->setFlag(QGraphicsItem::ItemClipsToShape);
+ bottomLeftGrandChild->setPos(0, -60);
+ grandChildRegion += QRect(0, 200 - 60, 160, 160);
+
+ QGraphicsRectItem *bottomRightChild = new QGraphicsRectItem(0, 0, 100, 100);
+ bottomRightChild->setBrush(Qt::red);
+ bottomRightChild->setParentItem(parent);
+ bottomRightChild->setPos(200, 200);
+ childRegion += QRect(200, 200, 100, 100);
+
+ QPoint controlPoints[17] = {
+ QPoint(5, 5) , QPoint(95, 5) , QPoint(205, 5) , QPoint(295, 5) ,
+ QPoint(5, 95) , QPoint(95, 95) , QPoint(205, 95) , QPoint(295, 95) ,
+ QPoint(150, 150),
+ QPoint(5, 205), QPoint(95, 205), QPoint(205, 205), QPoint(295, 205),
+ QPoint(5, 295), QPoint(95, 295), QPoint(205, 295), QPoint(295, 295),
+ };
+
+ const QRegion clippedChildRegion = childRegion & QRect(50, 50, 200, 200);
+ const QRegion clippedGrandChildRegion = grandChildRegion & QRect(50, 50, 200, 200);
+
+ QGraphicsScene scene;
+ scene.addItem(parent);
+ QImage sceneImage(300, 300, QImage::Format_ARGB32);
+
+#define VERIFY_CONTROL_POINTS(pRegion, cRegion, gRegion) \
+ for (int i = 0; i < 17; ++i) { \
+ QPoint controlPoint = controlPoints[i]; \
+ QRgb pixel = sceneImage.pixel(controlPoint.x(), controlPoint.y()); \
+ if (pRegion.contains(controlPoint)) \
+ QVERIFY(qBlue(pixel) != 0); \
+ else \
+ QVERIFY(qBlue(pixel) == 0); \
+ if (cRegion.contains(controlPoint)) \
+ QVERIFY(qRed(pixel) != 0); \
+ else \
+ QVERIFY(qRed(pixel) == 0); \
+ if (gRegion.contains(controlPoint)) \
+ QVERIFY(qGreen(pixel) != 0); \
+ else \
+ QVERIFY(qGreen(pixel) == 0); \
+ }
+
+ const QList<QGraphicsItem *> children = parent->childItems();
+ const int childrenCount = children.count();
+
+ for (int i = 0; i < 5; ++i) {
+ QString clipString;
+ QString childString;
+ switch (i) {
+ case 0:
+ // All children stacked in front.
+ childString = QLatin1String("ChildrenInFront.png");
+ foreach (QGraphicsItem *child, children)
+ child->setFlag(QGraphicsItem::ItemStacksBehindParent, false);
+ break;
+ case 1:
+ // All children stacked behind.
+ childString = QLatin1String("ChildrenBehind.png");
+ foreach (QGraphicsItem *child, children)
+ child->setFlag(QGraphicsItem::ItemStacksBehindParent, true);
+ break;
+ case 2:
+ // First half of the children behind, second half in front.
+ childString = QLatin1String("FirstHalfBehind_SecondHalfInFront.png");
+ for (int j = 0; j < childrenCount; ++j) {
+ QGraphicsItem *child = children.at(j);
+ child->setFlag(QGraphicsItem::ItemStacksBehindParent, (j < childrenCount / 2));
+ }
+ break;
+ case 3:
+ // First half of the children in front, second half behind.
+ childString = QLatin1String("FirstHalfInFront_SecondHalfBehind.png");
+ for (int j = 0; j < childrenCount; ++j) {
+ QGraphicsItem *child = children.at(j);
+ child->setFlag(QGraphicsItem::ItemStacksBehindParent, (j >= childrenCount / 2));
+ }
+ break;
+ case 4:
+ // Child2 and child4 behind, rest in front.
+ childString = QLatin1String("Child2And4Behind_RestInFront.png");
+ for (int j = 0; j < childrenCount; ++j) {
+ QGraphicsItem *child = children.at(j);
+ if (j == 1 || j == 3)
+ child->setFlag(QGraphicsItem::ItemStacksBehindParent, true);
+ else
+ child->setFlag(QGraphicsItem::ItemStacksBehindParent, false);
+ }
+ break;
+ default:
+ qFatal("internal error");
+ }
+
+ // Nothing is clipped.
+ parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
+ parent->setFlag(QGraphicsItem::ItemClipsToShape, false);
+ clipString = QLatin1String("nothingClipped_");
+ renderSceneToImage(&scene, &sceneImage, clipString + childString);
+ VERIFY_CONTROL_POINTS(parentRegion, childRegion, grandChildRegion);
+
+ // Parent clips children to shape.
+ parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+ clipString = QLatin1String("parentClipsChildrenToShape_");
+ renderSceneToImage(&scene, &sceneImage, clipString + childString);
+ VERIFY_CONTROL_POINTS(parentRegion, clippedChildRegion, clippedGrandChildRegion);
+
+ // Parent clips itself and children to shape.
+ parent->setFlag(QGraphicsItem::ItemClipsToShape);
+ clipString = QLatin1String("parentClipsItselfAndChildrenToShape_");
+ renderSceneToImage(&scene, &sceneImage, clipString + childString);
+ VERIFY_CONTROL_POINTS(clippedParentRegion, clippedChildRegion, clippedGrandChildRegion);
+
+ // Parent clips itself to shape.
+ parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
+ clipString = QLatin1String("parentClipsItselfToShape_");
+ renderSceneToImage(&scene, &sceneImage, clipString + childString);
+ VERIFY_CONTROL_POINTS(clippedParentRegion, childRegion, grandChildRegion);
+ }
+}
+
void tst_QGraphicsItem::itemClipsTextChildToShape()
{
// Construct a scene with a rect that clips its children, with one text
diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp
index 7b5ac7a..af02c55 100644
--- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp
+++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp
@@ -2492,25 +2492,31 @@ void tst_QGraphicsView::optimizationFlags_dontSavePainterState()
void tst_QGraphicsView::optimizationFlags_dontSavePainterState2_data()
{
QTest::addColumn<bool>("savePainter");
- QTest::newRow("With painter state protection") << true;
- QTest::newRow("Without painter state protection") << false;
+ QTest::addColumn<bool>("indirectPainting");
+ QTest::newRow("With painter state protection, without indirect painting") << true << false;
+ QTest::newRow("Without painter state protection, without indirect painting") << false << false;
+ QTest::newRow("With painter state protectionm, with indirect painting") << true << true;
+ QTest::newRow("Without painter state protection, with indirect painting") << false << true;
}
void tst_QGraphicsView::optimizationFlags_dontSavePainterState2()
{
QFETCH(bool, savePainter);
+ QFETCH(bool, indirectPainting);
class MyScene : public QGraphicsScene
{
public:
void drawBackground(QPainter *p, const QRectF &)
- { transformInDrawBackground = p->worldTransform(); }
+ { transformInDrawBackground = p->worldTransform(); opacityInDrawBackground = p->opacity(); }
void drawForeground(QPainter *p, const QRectF &)
- { transformInDrawForeground = p->worldTransform(); }
+ { transformInDrawForeground = p->worldTransform(); opacityInDrawForeground = p->opacity(); }
QTransform transformInDrawBackground;
QTransform transformInDrawForeground;
+ qreal opacityInDrawBackground;
+ qreal opacityInDrawForeground;
};
MyScene scene;
@@ -2518,9 +2524,13 @@ void tst_QGraphicsView::optimizationFlags_dontSavePainterState2()
scene.addRect(0, 0, 20, 20)->setTransform(QTransform::fromScale(2, 2));
scene.addRect(50, 50, 20, 20)->setTransform(QTransform::fromTranslate(200, 200));
+ foreach (QGraphicsItem *item, scene.items())
+ item->setOpacity(0.6);
+
CustomView view(&scene);
if (!savePainter)
view.setOptimizationFlag(QGraphicsView::DontSavePainterState);
+ view.setOptimizationFlag(QGraphicsView::IndirectPainting, indirectPainting);
view.rotate(45);
view.scale(1.5, 1.5);
view.show();
@@ -2534,10 +2544,38 @@ void tst_QGraphicsView::optimizationFlags_dontSavePainterState2()
QVERIFY(view.painted);
// Make sure the painter's world transform is preserved after drawItems.
- const QTransform expectedTransform = view.viewportTransform();
+ QTransform expectedTransform = view.viewportTransform();
QVERIFY(!expectedTransform.isIdentity());
QCOMPARE(scene.transformInDrawForeground, expectedTransform);
QCOMPARE(scene.transformInDrawBackground, expectedTransform);
+
+ qreal expectedOpacity = 1.0;
+ QCOMPARE(scene.opacityInDrawBackground, expectedOpacity);
+ QCOMPARE(scene.opacityInDrawForeground, expectedOpacity);
+
+ // Trigger more painting, this time from QGraphicsScene::render.
+ QImage image(scene.sceneRect().size().toSize(), QImage::Format_RGB32);
+ QPainter painter(&image);
+ scene.render(&painter);
+ painter.end();
+
+ expectedTransform = QTransform();
+ QCOMPARE(scene.transformInDrawForeground, expectedTransform);
+ QCOMPARE(scene.transformInDrawBackground, expectedTransform);
+ QCOMPARE(scene.opacityInDrawBackground, expectedOpacity);
+ QCOMPARE(scene.opacityInDrawForeground, expectedOpacity);
+
+ // Trigger more painting with another opacity on the painter.
+ painter.begin(&image);
+ painter.setOpacity(0.4);
+ expectedOpacity = 0.4;
+ scene.render(&painter);
+ painter.end();
+
+ QCOMPARE(scene.transformInDrawForeground, expectedTransform);
+ QCOMPARE(scene.transformInDrawBackground, expectedTransform);
+ QCOMPARE(scene.opacityInDrawBackground, expectedOpacity);
+ QCOMPARE(scene.opacityInDrawForeground, expectedOpacity);
}
class LodItem : public QGraphicsRectItem
diff --git a/tests/auto/qthread/tst_qthread.cpp b/tests/auto/qthread/tst_qthread.cpp
index 7a5b053..843749a 100644
--- a/tests/auto/qthread/tst_qthread.cpp
+++ b/tests/auto/qthread/tst_qthread.cpp
@@ -49,6 +49,7 @@
#include <qtimer.h>
#include <qwaitcondition.h>
#include <qdebug.h>
+#include <qmetaobject.h>
#ifdef Q_OS_UNIX
#include <pthread.h>
@@ -104,6 +105,8 @@ private slots:
void adoptedThreadFinished();
void adoptMultipleThreads();
+ void QTBUG13810_exitAndStart();
+
void stressTest();
};
@@ -934,6 +937,44 @@ void tst_QThread::stressTest()
}
}
+class Syncronizer : public QObject
+{ Q_OBJECT
+public slots:
+ void setProp(int p) {
+ if(m_prop != p) {
+ m_prop = p;
+ emit propChanged(p);
+ }
+ }
+signals:
+ void propChanged(int);
+public:
+ Syncronizer() : m_prop(42) {}
+ int m_prop;
+};
+
+void tst_QThread::QTBUG13810_exitAndStart()
+{
+ QThread thread;
+ thread.exit(555); //should do nothing
+
+ thread.start();
+
+ //test that the thread is running by executing queued connected signal there
+ Syncronizer sync1;
+ sync1.moveToThread(&thread);
+ Syncronizer sync2;
+ sync2.moveToThread(&thread);
+ connect(&sync2, SIGNAL(propChanged(int)), &sync1, SLOT(setProp(int)), Qt::QueuedConnection);
+ connect(&sync1, SIGNAL(propChanged(int)), &thread, SLOT(quit()), Qt::QueuedConnection);
+ QMetaObject::invokeMethod(&sync2, "setProp", Qt::QueuedConnection , Q_ARG(int, 89));
+ QTest::qWait(50);
+ while(!thread.wait(10))
+ QTest::qWait(10);
+ QCOMPARE(sync2.m_prop, 89);
+ QCOMPARE(sync1.m_prop, 89);
+}
+
QTEST_MAIN(tst_QThread)
#include "tst_qthread.moc"
diff --git a/tests/auto/qtreeview/tst_qtreeview.cpp b/tests/auto/qtreeview/tst_qtreeview.cpp
index 7e2e800..c7b53e9 100644
--- a/tests/auto/qtreeview/tst_qtreeview.cpp
+++ b/tests/auto/qtreeview/tst_qtreeview.cpp
@@ -240,6 +240,7 @@ private slots:
void taskQTBUG_6450_selectAllWith1stColumnHidden();
void taskQTBUG_9216_setSizeAndUniformRowHeightsWrongRepaint();
void taskQTBUG_11466_keyboardNavigationRegression();
+ void taskQTBUG_13567_removeLastItemRegression();
};
class QtTestModel: public QAbstractItemModel
@@ -3910,5 +3911,26 @@ void tst_QTreeView::taskQTBUG_11466_keyboardNavigationRegression()
QTRY_COMPARE(treeView.currentIndex(), treeView.selectionModel()->selection().indexes().first());
}
+void tst_QTreeView::taskQTBUG_13567_removeLastItemRegression()
+{
+ QtTestModel model(200, 1);
+
+ QTreeView view;
+ view.setSelectionMode(QAbstractItemView::ExtendedSelection);
+ view.setModel(&model);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+
+ view.scrollToBottom();
+ QTest::qWait(10);
+ CHECK_VISIBLE(199, 0);
+
+ view.setCurrentIndex(model.index(199, 0));
+ model.removeLastRow();
+ QTest::qWait(10);
+ QCOMPARE(view.currentIndex(), model.index(198, 0));
+ CHECK_VISIBLE(198, 0);
+}
+
QTEST_MAIN(tst_QTreeView)
#include "tst_qtreeview.moc"