From 0095e40b2efc0c43c0d908bb5b9828619bc087e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Nilsen?= Date: Mon, 8 Jun 2009 13:09:14 +0200 Subject: QGraphicsItem discard updates when it shouldn't. Once a _q_processDirtyItems call is queued, it means we at least have one item that is marked as dirty and we must reset it when the _q_processDirtyItems slot is called. The problem however, was that we didn't reset the item's dirty state if a full scene update occurred in between, i.e. item->update(); scene.update(); We don't have to calculate the item's dirty rect if a full scene update occurs in between, but we still have to reset its state. Auto-test included. --- src/gui/graphicsview/qgraphicsscene.cpp | 13 ++++++------ src/gui/graphicsview/qgraphicsview.cpp | 1 + tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 28 ++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index caf9309..ad392b0 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -679,19 +679,19 @@ void QGraphicsScenePrivate::_q_processDirtyItems() { processDirtyItemsEmitted = false; - if (updateAll) - return; - const bool wasPendingSceneUpdate = calledEmitUpdated; const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect; processDirtyItemsRecursive(0); if (!hasSceneRect && oldGrowingItemsBoundingRect != growingItemsBoundingRect) emit q_func()->sceneRectChanged(growingItemsBoundingRect); + if (wasPendingSceneUpdate) + return; + for (int i = 0; i < views.size(); ++i) views.at(i)->d_func()->processPendingUpdates(); - if (!wasPendingSceneUpdate && calledEmitUpdated) { + if (calledEmitUpdated) { // We did a compatibility QGraphicsScene::update in processDirtyItemsRecursive // and we cannot wait for the control to reach the eventloop before the // changed signal is emitted, so we emit it now. @@ -5322,7 +5322,6 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren) { - Q_ASSERT(!item || item->d_ptr->dirty || item->d_ptr->dirtyChildren); Q_Q(QGraphicsScene); // Calculate the full scene transform for this item. @@ -5438,13 +5437,15 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool continue; } - if (dirtyAncestorContainsChildren) { + if (dirtyAncestorContainsChildren || updateAll) { // No need to process this child's dirty rect, hence reset the dirty state. // However, we have to continue the recursion because it might have a dirty // view bounding rect that needs repaint. We also have to reset the dirty // state of its descendants. child->d_ptr->dirty = 0; child->d_ptr->fullUpdatePending = 0; + if (updateAll) + child->d_ptr->paintedViewBoundingRectsNeedRepaint = 0; } processDirtyItemsRecursive(child, dirtyAncestorContainsChildren); diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 87b5e3f..a9fc563 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -2496,6 +2496,7 @@ void QGraphicsView::updateScene(const QList &rects) for (int i = 0; i < dirtyRects.size(); ++i) dirtyViewportRects += dirtyRects.at(i); d->dirtyRegion = QRegion(); + d->dirtyBoundingRect = QRect(); bool fullUpdate = !d->accelerateScrolling || d->viewportUpdateMode == QGraphicsView::FullViewportUpdate; bool boundingRectUpdate = (d->viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate) diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 427ecf3..5b297f6 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -219,6 +219,7 @@ private slots: void updateCachedItemAfterMove(); void deviceTransform_data(); void deviceTransform(); + void update(); // task specific tests below me void task141694_textItemEnsureVisible(); @@ -6427,5 +6428,32 @@ void tst_QGraphicsItem::deviceTransform() QCOMPARE(rect3->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult3); } +void tst_QGraphicsItem::update() +{ + QGraphicsScene scene; + QGraphicsView view(&scene); + view.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(100); + + EventTester *item = new EventTester; + scene.addItem(item); + QTest::qWait(100); // Make sure all pending updates are processed. + item->repaints = 0; + + item->update(); // Item marked as dirty + scene.update(); // Entire scene marked as dirty + qApp->processEvents(); + QCOMPARE(item->repaints, 1); + + // Make sure the dirty state from the previous update is reset so that + // the item don't think it is already dirty and discards this update. + item->update(); + qApp->processEvents(); + QCOMPARE(item->repaints, 2); +} + QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc" -- cgit v0.12