summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Erik Nilsen <bjorn.nilsen@nokia.com>2010-04-16 12:52:05 (GMT)
committerBjørn Erik Nilsen <bjorn.nilsen@nokia.com>2010-04-16 14:58:08 (GMT)
commit8ebcd4db8d57b7e90ec86c9290682ee9c2e576b7 (patch)
treeb1a001064ec08a3dc64e098e635255af100105ce
parent74f28819d985984170964d12d8f527034db93017 (diff)
downloadQt-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.cpp70
-rw-r--r--src/gui/painting/qbackingstore_p.h4
-rw-r--r--src/gui/painting/qwindowsurface.cpp28
-rw-r--r--src/gui/painting/qwindowsurface_p.h2
-rw-r--r--tests/auto/qwindowsurface/tst_qwindowsurface.cpp48
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 &region);
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