diff options
author | Bjørn Erik Nilsen <bjorn.nilsen@nokia.com> | 2010-04-16 12:52:05 (GMT) |
---|---|---|
committer | Bjørn Erik Nilsen <bjorn.nilsen@nokia.com> | 2010-04-16 14:58:08 (GMT) |
commit | 8ebcd4db8d57b7e90ec86c9290682ee9c2e576b7 (patch) | |
tree | b1a001064ec08a3dc64e098e635255af100105ce | |
parent | 74f28819d985984170964d12d8f527034db93017 (diff) | |
download | Qt-8ebcd4db8d57b7e90ec86c9290682ee9c2e576b7.zip Qt-8ebcd4db8d57b7e90ec86c9290682ee9c2e576b7.tar.gz Qt-8ebcd4db8d57b7e90ec86c9290682ee9c2e576b7.tar.bz2 |
Some QWindowSurface implementations might implement flush as a buffer
flip. Such window surfaces therefore destroy the contents during flush.
In order to render correctly on these surfaces, any update, no matter
how small, needs to trigger the entire window to be redrawn.
Auto test included.
Task-number: Relates to QTBUG-9978
Reviewed-by: tom
-rw-r--r-- | src/gui/painting/qbackingstore.cpp | 70 | ||||
-rw-r--r-- | src/gui/painting/qbackingstore_p.h | 4 | ||||
-rw-r--r-- | src/gui/painting/qwindowsurface.cpp | 28 | ||||
-rw-r--r-- | src/gui/painting/qwindowsurface_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qwindowsurface/tst_qwindowsurface.cpp | 48 |
5 files changed, 128 insertions, 24 deletions
diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp index 8de9eaa..f9cd59b 100644 --- a/src/gui/painting/qbackingstore.cpp +++ b/src/gui/painting/qbackingstore.cpp @@ -263,7 +263,7 @@ bool QWidgetBackingStore::bltRect(const QRect &rect, int dx, int dy, QWidget *wi { const QPoint pos(tlwOffset + widget->mapTo(tlw, rect.topLeft())); const QRect tlwRect(QRect(pos, rect.size())); - if (dirty.intersects(tlwRect)) + if (fullUpdatePending || dirty.intersects(tlwRect)) return false; // We don't want to scroll junk. return windowSurface->scroll(tlwRect, dx, dy); } @@ -402,7 +402,7 @@ QRegion QWidgetBackingStore::dirtyRegion(QWidget *widget) const const bool widgetDirty = widget && widget != tlw; const QRect tlwRect(topLevelRect()); const QRect surfaceGeometry(windowSurface->geometry()); - if (surfaceGeometry != tlwRect && surfaceGeometry.size() != tlwRect.size()) { + if (fullUpdatePending || (surfaceGeometry != tlwRect && surfaceGeometry.size() != tlwRect.size())) { if (widgetDirty) { const QRect dirtyTlwRect = QRect(QPoint(), tlwRect.size()); const QPoint offset(widget->mapTo(tlw, QPoint())); @@ -555,6 +555,18 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up return; } + if (fullUpdatePending) { + if (updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; + } + + if (!windowSurface->hasPartialUpdateSupport()) { + fullUpdatePending = true; + sendUpdateRequest(tlw, updateImmediately); + return; + } + const QPoint offset = widget->mapTo(tlw, QPoint()); const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect()); if (qt_region_strictContains(dirty, widgetRect.translated(offset))) { @@ -638,6 +650,18 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool upd return; } + if (fullUpdatePending) { + if (updateImmediately) + sendUpdateRequest(tlw, updateImmediately); + return; + } + + if (!windowSurface->hasPartialUpdateSupport()) { + fullUpdatePending = true; + sendUpdateRequest(tlw, updateImmediately); + return; + } + const QRect widgetRect = widget->d_func()->effectiveRectFor(rect); const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint()))); if (qt_region_strictContains(dirty, translatedRect)) { @@ -833,6 +857,7 @@ void QWidgetBackingStore::updateLists(QWidget *cur) QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel) : tlw(topLevel), dirtyOnScreenWidgets(0), hasDirtyFromPreviousSync(false) + , fullUpdatePending(0) { windowSurface = tlw->windowSurface(); if (!windowSurface) @@ -1122,6 +1147,7 @@ void QWidgetBackingStore::sync() for (int i = 0; i < dirtyWidgets.size(); ++i) resetWidget(dirtyWidgets.at(i)); dirtyWidgets.clear(); + fullUpdatePending = false; } return; } @@ -1132,28 +1158,28 @@ void QWidgetBackingStore::sync() const QRect surfaceGeometry(windowSurface->geometry()); bool repaintAllWidgets = false; - if (inTopLevelResize || surfaceGeometry != tlwRect) { - if ((inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) { - if (hasStaticContents()) { - // Repaint existing dirty area and newly visible area. - const QRect clipRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); - const QRegion staticRegion(staticContents(0, clipRect)); - QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height()); - newVisible -= staticRegion; - dirty += newVisible; - windowSurface->setStaticContents(staticRegion); - } else { - // Repaint everything. - dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height()); - for (int i = 0; i < dirtyWidgets.size(); ++i) - resetWidget(dirtyWidgets.at(i)); - dirtyWidgets.clear(); - repaintAllWidgets = true; - } + if ((fullUpdatePending || inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) { + if (hasStaticContents()) { + // Repaint existing dirty area and newly visible area. + const QRect clipRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); + const QRegion staticRegion(staticContents(0, clipRect)); + QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height()); + newVisible -= staticRegion; + dirty += newVisible; + windowSurface->setStaticContents(staticRegion); + } else { + // Repaint everything. + dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height()); + for (int i = 0; i < dirtyWidgets.size(); ++i) + resetWidget(dirtyWidgets.at(i)); + dirtyWidgets.clear(); + repaintAllWidgets = true; } - windowSurface->setGeometry(tlwRect); } + if (inTopLevelResize || surfaceGeometry != tlwRect) + windowSurface->setGeometry(tlwRect); + if (updatesDisabled) return; @@ -1212,6 +1238,8 @@ void QWidgetBackingStore::sync() } dirtyWidgets.clear(); + fullUpdatePending = false; + if (toClean.isEmpty()) { // Nothing to repaint. However, we might have newly exposed areas on the // screen if this function was called from sync(QWidget *, QRegion)), so diff --git a/src/gui/painting/qbackingstore_p.h b/src/gui/painting/qbackingstore_p.h index 02c0f7c..6510b57 100644 --- a/src/gui/painting/qbackingstore_p.h +++ b/src/gui/painting/qbackingstore_p.h @@ -91,6 +91,7 @@ public: inline bool isDirty() const { return !(dirtyWidgets.isEmpty() && dirty.isEmpty() && !hasDirtyFromPreviousSync + && !fullUpdatePending #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) && !hasDirtyWindowDecoration() #endif @@ -115,7 +116,8 @@ private: #ifdef Q_BACKINGSTORE_SUBSURFACES QList<QWindowSurface*> subSurfaces; #endif - bool hasDirtyFromPreviousSync; + uint hasDirtyFromPreviousSync : 1; + uint fullUpdatePending : 1; QPoint tlwOffset; diff --git a/src/gui/painting/qwindowsurface.cpp b/src/gui/painting/qwindowsurface.cpp index 8bd6344..e18ea3f 100644 --- a/src/gui/painting/qwindowsurface.cpp +++ b/src/gui/painting/qwindowsurface.cpp @@ -49,13 +49,19 @@ QT_BEGIN_NAMESPACE class QWindowSurfacePrivate { public: - QWindowSurfacePrivate(QWidget *w) : window(w), staticContentsSupport(false) {} + QWindowSurfacePrivate(QWidget *w) + : window(w) + , staticContentsSupport(0) + , partialUpdateSupport(1) + { + } QWidget *window; QRect geometry; QRegion staticContents; QList<QImage*> bufferImages; - bool staticContentsSupport; + uint staticContentsSupport : 1; + uint partialUpdateSupport : 1; }; /*! @@ -284,6 +290,10 @@ bool QWindowSurface::hasStaticContentsSupport() const void QWindowSurface::setStaticContentsSupport(bool enable) { + if (enable && !d_ptr->partialUpdateSupport) { + qWarning("QWindowSurface::setStaticContentsSupport: static contents support requires partial update support"); + return; + } d_ptr->staticContentsSupport = enable; } @@ -302,6 +312,20 @@ bool QWindowSurface::hasStaticContents() const return d_ptr->staticContentsSupport && !d_ptr->staticContents.isEmpty(); } +bool QWindowSurface::hasPartialUpdateSupport() const +{ + return d_ptr->partialUpdateSupport; +} + +void QWindowSurface::setPartialUpdateSupport(bool enable) +{ + if (!enable && d_ptr->staticContentsSupport) { + qWarning("QWindowSurface::setPartialUpdateSupport: static contents support requires partial update support"); + return; + } + d_ptr->partialUpdateSupport = enable; +} + void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset) { // make sure we don't detach diff --git a/src/gui/painting/qwindowsurface_p.h b/src/gui/painting/qwindowsurface_p.h index 0a453af..e6ee5f6 100644 --- a/src/gui/painting/qwindowsurface_p.h +++ b/src/gui/painting/qwindowsurface_p.h @@ -90,6 +90,7 @@ public: inline QRect rect(const QWidget *widget) const; bool hasStaticContentsSupport() const; + bool hasPartialUpdateSupport() const; void setStaticContents(const QRegion ®ion); QRegion staticContents() const; @@ -97,6 +98,7 @@ public: protected: bool hasStaticContents() const; void setStaticContentsSupport(bool enable); + void setPartialUpdateSupport(bool enable); private: QWindowSurfacePrivate *d_ptr; diff --git a/tests/auto/qwindowsurface/tst_qwindowsurface.cpp b/tests/auto/qwindowsurface/tst_qwindowsurface.cpp index dd985ca..7dde402 100644 --- a/tests/auto/qwindowsurface/tst_qwindowsurface.cpp +++ b/tests/auto/qwindowsurface/tst_qwindowsurface.cpp @@ -66,6 +66,7 @@ private slots: void getSetWindowSurface(); void flushOutsidePaintEvent(); void grabWidget(); + void staticContentsAndPartialUpdateSupport(); }; class MyWindowSurface : public QWindowSurface @@ -81,6 +82,8 @@ public: /* nothing */ } + using QWindowSurface::setStaticContentsSupport; + using QWindowSurface::setPartialUpdateSupport; private: QImage image; }; @@ -280,6 +283,51 @@ void tst_QWindowSurface::grabWidget() QVERIFY(QColor(childInvalidSubImage.pixel(0, 0)) == QColor(Qt::white)); } +void tst_QWindowSurface::staticContentsAndPartialUpdateSupport() +{ + QWidget widget; + MyWindowSurface surface(&widget); + + // Default values. + QVERIFY(surface.hasPartialUpdateSupport()); + QVERIFY(!surface.hasStaticContentsSupport()); + + // Partial: YES, Static: YES + surface.setStaticContentsSupport(true); + QVERIFY(surface.hasPartialUpdateSupport()); + QVERIFY(surface.hasStaticContentsSupport()); + + // Static contents requires support for partial updates. + // We simply ingore bad combinations and spit out a warning. + + // CONFLICT: Partial: NO, Static: YES + QTest::ignoreMessage(QtWarningMsg, "QWindowSurface::setPartialUpdateSupport: static contents support requires partial update support"); + surface.setPartialUpdateSupport(false); + QVERIFY(surface.hasPartialUpdateSupport()); + QVERIFY(surface.hasStaticContentsSupport()); + + // Partial: YES, Static: NO + surface.setStaticContentsSupport(false); + QVERIFY(surface.hasPartialUpdateSupport()); + QVERIFY(!surface.hasStaticContentsSupport()); + + // Partial: NO, Static: NO + surface.setPartialUpdateSupport(false); + QVERIFY(!surface.hasPartialUpdateSupport()); + QVERIFY(!surface.hasStaticContentsSupport()); + + // CONFLICT: Partial: NO, Static: YES + QTest::ignoreMessage(QtWarningMsg, "QWindowSurface::setStaticContentsSupport: static contents support requires partial update support"); + surface.setStaticContentsSupport(true); + QVERIFY(!surface.hasPartialUpdateSupport()); + QVERIFY(!surface.hasStaticContentsSupport()); + + // Partial: YES, Static: NO + surface.setPartialUpdateSupport(true); + QVERIFY(surface.hasPartialUpdateSupport()); + QVERIFY(!surface.hasStaticContentsSupport()); +} + QTEST_MAIN(tst_QWindowSurface) #else // Q_WS_MAC |