1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
43 #include "qplatformdefs.h"
45 #include "qbackingstore_p.h"
47 #include <QtCore/qglobal.h>
48 #include <QtCore/qdebug.h>
49 #include <QtCore/qvarlengtharray.h>
50 #include <QtGui/qevent.h>
51 #include <QtGui/qapplication.h>
52 #include <QtGui/qpaintengine.h>
53 #include <QtGui/qgraphicsproxywidget.h>
55 #include <private/qwidget_p.h>
56 #include <private/qwindowsurface_raster_p.h>
57 #include <private/qapplication_p.h>
58 #include <private/qpaintengine_raster_p.h>
59 #include <private/qgraphicseffect_p.h>
61 #include "qgraphicssystem_p.h"
64 #include <QtGui/qwsmanager_qws.h>
65 #include <private/qwsmanager_p.h>
70 extern QRegion qt_dirtyRegion(QWidget *);
73 A version of QRect::intersects() that does not normalize the rects.
75 static inline bool qRectIntersects(const QRect &r1, const QRect &r2)
77 return (qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right())
78 && qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom()));
82 * Flushes the contents of the \a windowSurface into the screen area of \a widget.
83 * \a tlwOffset is the position of the top level widget relative to the window surface.
84 * \a region is the region to be updated in \a widget coordinates.
86 static inline void qt_flush(QWidget *widget, const QRegion ®ion, QWindowSurface *windowSurface,
87 QWidget *tlw, const QPoint &tlwOffset)
90 Q_ASSERT(!region.isEmpty());
91 Q_ASSERT(windowSurface);
94 #if !defined(QT_NO_PAINT_DEBUG) && !defined(Q_WS_QWS)
95 // QWS does flush update in QWindowSurface::flush (because it needs to lock the surface etc).
96 static int flushUpdate = qgetenv("QT_FLUSH_UPDATE").toInt();
98 QWidgetBackingStore::showYellowThing(widget, region, flushUpdate * 10, false);
101 //The performance hit by doing this should be negligible. However, be aware that
102 //using this FPS when you have > 1 windowsurface can give you inaccurate FPS
103 static bool fpsDebug = qgetenv("QT_DEBUG_FPS").toInt();
105 static QTime time = QTime::currentTime();
106 static int frames = 0;
110 if(time.elapsed() > 5000) {
111 double fps = double(frames * 1000) /time.restart();
112 fprintf(stderr,"FPS: %.1f\n",fps);
117 windowSurface->flush(widget, region, tlwOffset + widget->mapTo(tlw, QPoint()));
119 windowSurface->flush(widget, region, tlwOffset);
122 #ifndef QT_NO_PAINT_DEBUG
124 static void showYellowThing_win(QWidget *widget, const QRegion ®ion, int msec)
130 brush = CreateSolidBrush(RGB(255, 255, 0));
133 brush = CreateSolidBrush(RGB(255, 200, 55));
136 brush = CreateSolidBrush(RGB(200, 255, 55));
139 brush = CreateSolidBrush(RGB(200, 200, 0));
144 HDC hdc = widget->getDC();
146 const QVector<QRect> &rects = region.rects();
147 foreach (QRect rect, rects) {
149 SetRect(&winRect, rect.left(), rect.top(), rect.right(), rect.bottom());
150 FillRect(hdc, &winRect, brush);
153 widget->releaseDC(hdc);
158 void QWidgetBackingStore::showYellowThing(QWidget *widget, const QRegion &toBePainted, int msec, bool unclipped)
163 static QWSYellowSurface surface(true);
164 surface.setDelay(msec);
165 surface.flush(widget, toBePainted, QPoint());
167 QRegion paintRegion = toBePainted;
168 QRect widgetRect = widget->rect();
170 if (!widget->internalWinId()) {
171 QWidget *nativeParent = widget->nativeParentWidget();
172 const QPoint offset = widget->mapTo(nativeParent, QPoint(0, 0));
173 paintRegion.translate(offset);
174 widgetRect.translate(offset);
175 widget = nativeParent;
180 showYellowThing_win(widget, paintRegion, msec);
182 //flags to fool painter
183 bool paintUnclipped = widget->testAttribute(Qt::WA_PaintUnclipped);
184 if (unclipped && !widget->d_func()->paintOnScreen())
185 widget->setAttribute(Qt::WA_PaintUnclipped);
187 const bool setFlag = !widget->testAttribute(Qt::WA_WState_InPaintEvent);
189 widget->setAttribute(Qt::WA_WState_InPaintEvent);
192 QPaintEngine *pe = widget->paintEngine();
194 pe->setSystemClip(paintRegion);
197 p.setClipRegion(paintRegion);
201 p.fillRect(widgetRect, QColor(255,255,0));
204 p.fillRect(widgetRect, QColor(255,200,55));
207 p.fillRect(widgetRect, QColor(200,255,55));
210 p.fillRect(widgetRect, QColor(200,200,0));
219 widget->setAttribute(Qt::WA_WState_InPaintEvent, false);
222 widget->setAttribute(Qt::WA_PaintUnclipped, paintUnclipped);
225 pe->setSystemClip(QRegion());
227 QApplication::syncX();
229 #if defined(Q_OS_UNIX)
230 ::usleep(1000 * msec);
236 bool QWidgetBackingStore::flushPaint(QWidget *widget, const QRegion &rgn)
242 if (widget->testAttribute(Qt::WA_WState_InPaintEvent)) {
243 static int flushPaintEvent = qgetenv("QT_FLUSH_PAINT_EVENT").toInt();
244 if (!flushPaintEvent)
246 delay = flushPaintEvent;
248 static int flushPaint = qgetenv("QT_FLUSH_PAINT").toInt();
254 QWidgetBackingStore::showYellowThing(widget, rgn, delay * 10, true);
258 void QWidgetBackingStore::unflushPaint(QWidget *widget, const QRegion &rgn)
260 if (widget->d_func()->paintOnScreen() || rgn.isEmpty())
263 QWidget *tlw = widget->window();
264 QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
268 const QPoint offset = widget->mapTo(tlw, QPoint());
269 qt_flush(widget, rgn, tlwExtra->backingStore->windowSurface, tlw, offset);
271 #endif // QT_NO_PAINT_DEBUG
274 Moves the whole rect by (dx, dy) in widget's coordinate system.
275 Doesn't generate any updates.
277 bool QWidgetBackingStore::bltRect(const QRect &rect, int dx, int dy, QWidget *widget)
279 const QPoint pos(tlwOffset + widget->mapTo(tlw, rect.topLeft()));
280 const QRect tlwRect(QRect(pos, rect.size()));
281 if (fullUpdatePending || dirty.intersects(tlwRect))
282 return false; // We don't want to scroll junk.
283 return windowSurface->scroll(tlwRect, dx, dy);
286 void QWidgetBackingStore::releaseBuffer()
289 #if defined(Q_WS_QPA)
290 windowSurface->resize(QSize());
292 windowSurface->setGeometry(QRect());
294 #ifdef Q_BACKINGSTORE_SUBSURFACES
295 for (int i = 0; i < subSurfaces.size(); ++i)
296 subSurfaces.at(i)->setGeometry(QRect());
301 Prepares the window surface to paint a\ toClean region of the \a widget and
302 updates the BeginPaintInfo struct accordingly.
304 The \a toClean region might be clipped by the window surface.
306 void QWidgetBackingStore::beginPaint(QRegion &toClean, QWidget *widget, QWindowSurface *windowSurface,
307 BeginPaintInfo *returnInfo, bool toCleanIsInTopLevelCoordinates)
310 QWSWindowSurface *surface = static_cast<QWSWindowSurface *>(windowSurface);
311 QWidget *surfaceWidget = surface->window();
313 if (!surface->isValid()) {
314 // this looks strange but it really just releases the surface
315 surface->releaseSurface();
316 // the old window surface is deleted in setWindowSurface, which is
317 // called from QWindowSurface constructor.
318 windowSurface = tlw->d_func()->createDefaultWindowSurface();
319 surface = static_cast<QWSWindowSurface *>(windowSurface);
320 // createDefaultWindowSurface() will set topdata->windowSurface on the
321 // widget to zero. However, if this is a sub-surface, it should point
322 // to the widget's sub windowSurface, so we set that here:
323 if (!surfaceWidget->isWindow())
324 surfaceWidget->d_func()->topData()->windowSurface = windowSurface;
325 surface->setGeometry(topLevelRect());
326 returnInfo->windowSurfaceRecreated = true;
329 const QRegion toCleanUnclipped(toClean);
331 if (surfaceWidget->isWindow())
332 tlwOffset = surface->painterOffset();
333 #ifdef Q_BACKINGSTORE_SUBSURFACES
334 else if (toCleanIsInTopLevelCoordinates)
335 toClean &= surface->clipRegion().translated(surfaceWidget->mapTo(tlw, QPoint()));
336 if (!toCleanIsInTopLevelCoordinates && windowSurface == this->windowSurface)
337 toClean &= surface->clipRegion().translated(-widget->mapTo(surfaceWidget, QPoint()));
339 toClean &= surface->clipRegion();
342 if (toClean.isEmpty()) {
343 if (surfaceWidget->isWindow()) {
344 dirtyFromPreviousSync += toCleanUnclipped;
345 hasDirtyFromPreviousSync = true;
348 returnInfo->nothingToPaint = true;
349 // Nothing to repaint. However, we might have newly exposed areas on the
350 // screen, so we have to make sure those are flushed.
355 if (surfaceWidget->isWindow()) {
356 if (toCleanUnclipped != toClean) {
357 dirtyFromPreviousSync += (toCleanUnclipped - surface->clipRegion());
358 hasDirtyFromPreviousSync = true;
360 if (hasDirtyFromPreviousSync) {
361 dirtyFromPreviousSync -= toClean;
362 hasDirtyFromPreviousSync = !dirtyFromPreviousSync.isEmpty();
369 Q_UNUSED(toCleanIsInTopLevelCoordinates);
371 // Always flush repainted areas.
372 dirtyOnScreen += toClean;
374 #if defined(Q_WS_QWS) && !defined(Q_BACKINGSTORE_SUBSURFACES)
375 toClean.translate(tlwOffset);
378 #ifdef QT_NO_PAINT_DEBUG
379 windowSurface->beginPaint(toClean);
381 returnInfo->wasFlushed = QWidgetBackingStore::flushPaint(tlw, toClean);
382 // Avoid deadlock with QT_FLUSH_PAINT: the server will wait for
383 // the BackingStore lock, so if we hold that, the server will
384 // never release the Communication lock that we are waiting for in
385 // sendSynchronousCommand
386 if (!returnInfo->wasFlushed)
387 windowSurface->beginPaint(toClean);
390 Q_UNUSED(returnInfo);
393 void QWidgetBackingStore::endPaint(const QRegion &cleaned, QWindowSurface *windowSurface,
394 BeginPaintInfo *beginPaintInfo)
396 #ifndef QT_NO_PAINT_DEBUG
397 if (!beginPaintInfo->wasFlushed)
398 windowSurface->endPaint(cleaned);
400 QWidgetBackingStore::unflushPaint(tlw, cleaned);
402 Q_UNUSED(beginPaintInfo);
403 windowSurface->endPaint(cleaned);
406 #ifdef Q_BACKINGSTORE_SUBSURFACES
407 flush(static_cast<QWSWindowSurface *>(windowSurface)->window(), windowSurface);
414 Returns the region (in top-level coordinates) that needs repaint and/or flush.
416 If the widget is non-zero, only the dirty region for the widget is returned
417 and the region will be in widget coordinates.
419 QRegion QWidgetBackingStore::dirtyRegion(QWidget *widget) const
421 const bool widgetDirty = widget && widget != tlw;
422 const QRect tlwRect(topLevelRect());
423 #if defined(Q_WS_QPA)
424 const QRect surfaceGeometry(tlwRect.topLeft(), windowSurface->size());
426 const QRect surfaceGeometry(windowSurface->geometry());
428 if (fullUpdatePending || (surfaceGeometry != tlwRect && surfaceGeometry.size() != tlwRect.size())) {
430 const QRect dirtyTlwRect = QRect(QPoint(), tlwRect.size());
431 const QPoint offset(widget->mapTo(tlw, QPoint()));
432 const QRect dirtyWidgetRect(dirtyTlwRect & widget->rect().translated(offset));
433 return dirtyWidgetRect.translated(-offset);
435 return QRect(QPoint(), tlwRect.size());
438 // Calculate the region that needs repaint.
440 for (int i = 0; i < dirtyWidgets.size(); ++i) {
441 QWidget *w = dirtyWidgets.at(i);
442 if (widgetDirty && w != widget && !widget->isAncestorOf(w))
444 r += w->d_func()->dirty.translated(w->mapTo(tlw, QPoint()));
447 // Append the region that needs flush.
450 if (dirtyOnScreenWidgets) { // Only in use with native child widgets.
451 for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) {
452 QWidget *w = dirtyOnScreenWidgets->at(i);
453 if (widgetDirty && w != widget && !widget->isAncestorOf(w))
455 QWidgetPrivate *wd = w->d_func();
456 Q_ASSERT(wd->needsFlush);
457 r += wd->needsFlush->translated(w->mapTo(tlw, QPoint()));
462 // Intersect with the widget geometry and translate to its coordinates.
463 const QPoint offset(widget->mapTo(tlw, QPoint()));
464 r &= widget->rect().translated(offset);
465 r.translate(-offset);
471 Returns the static content inside the \a parent if non-zero; otherwise the static content
472 for the entire backing store is returned. The content will be clipped to \a withinClipRect
475 QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &withinClipRect) const
477 if (!parent && tlw->testAttribute(Qt::WA_StaticContents)) {
478 #if defined(Q_WS_QPA)
479 const QSize surfaceGeometry(windowSurface->size());
481 const QRect surfaceGeometry(windowSurface->geometry());
483 QRect surfaceRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height());
484 if (!withinClipRect.isEmpty())
485 surfaceRect &= withinClipRect;
486 return QRegion(surfaceRect);
490 if (parent && parent->d_func()->children.isEmpty())
493 const bool clipToRect = !withinClipRect.isEmpty();
494 const int count = staticWidgets.count();
495 for (int i = 0; i < count; ++i) {
496 QWidget *w = staticWidgets.at(i);
497 QWidgetPrivate *wd = w->d_func();
498 if (!wd->isOpaque || !wd->extra || wd->extra->staticContentsSize.isEmpty()
499 || !w->isVisible() || (parent && !parent->isAncestorOf(w))) {
503 QRect rect(0, 0, wd->extra->staticContentsSize.width(), wd->extra->staticContentsSize.height());
504 const QPoint offset = w->mapTo(parent ? parent : tlw, QPoint());
506 rect &= withinClipRect.translated(-offset);
510 rect &= wd->clipRect();
514 QRegion visible(rect);
515 wd->clipToEffectiveMask(visible);
516 if (visible.isEmpty())
518 wd->subtractOpaqueSiblings(visible, 0, /*alsoNonOpaque=*/true);
520 visible.translate(offset);
527 static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately)
532 if (updateImmediately) {
533 QEvent event(QEvent::UpdateRequest);
534 QApplication::sendEvent(widget, &event);
536 QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
541 Marks the region of the widget as dirty (if not already marked as dirty) and
542 posts an UpdateRequest event to the top-level widget (if not already posted).
544 If updateImmediately is true, the event is sent immediately instead of posted.
546 If invalidateBuffer is true, all widgets intersecting with the region will be dirty.
548 If the widget paints directly on screen, the event is sent to the widget
549 instead of the top-level widget, and invalidateBuffer is completely ignored.
551 ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
553 void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool updateImmediately,
554 bool invalidateBuffer)
556 Q_ASSERT(tlw->d_func()->extra);
557 Q_ASSERT(tlw->d_func()->extra->topextra);
558 Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize);
559 Q_ASSERT(widget->isVisible() && widget->updatesEnabled());
560 Q_ASSERT(widget->window() == tlw);
561 Q_ASSERT(!rgn.isEmpty());
563 #ifndef QT_NO_GRAPHICSEFFECT
564 widget->d_func()->invalidateGraphicsEffectsRecursively();
565 #endif //QT_NO_GRAPHICSEFFECT
567 if (widget->d_func()->paintOnScreen()) {
568 if (widget->d_func()->dirty.isEmpty()) {
569 widget->d_func()->dirty = rgn;
570 sendUpdateRequest(widget, updateImmediately);
572 } else if (qt_region_strictContains(widget->d_func()->dirty, widget->rect())) {
573 if (updateImmediately)
574 sendUpdateRequest(widget, updateImmediately);
575 return; // Already dirty.
578 const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty();
579 widget->d_func()->dirty += rgn;
580 if (!eventAlreadyPosted || updateImmediately)
581 sendUpdateRequest(widget, updateImmediately);
585 if (fullUpdatePending) {
586 if (updateImmediately)
587 sendUpdateRequest(tlw, updateImmediately);
591 if (!windowSurface->hasFeature(QWindowSurface::PartialUpdates)) {
592 fullUpdatePending = true;
593 sendUpdateRequest(tlw, updateImmediately);
597 const QPoint offset = widget->mapTo(tlw, QPoint());
598 const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect());
599 if (qt_region_strictContains(dirty, widgetRect.translated(offset))) {
600 if (updateImmediately)
601 sendUpdateRequest(tlw, updateImmediately);
602 return; // Already dirty.
605 if (invalidateBuffer) {
606 const bool eventAlreadyPosted = !dirty.isEmpty();
607 #ifndef QT_NO_GRAPHICSEFFECT
608 if (widget->d_func()->graphicsEffect)
609 dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset);
611 #endif //QT_NO_GRAPHICSEFFECT
612 dirty += rgn.translated(offset);
613 if (!eventAlreadyPosted || updateImmediately)
614 sendUpdateRequest(tlw, updateImmediately);
618 if (dirtyWidgets.isEmpty()) {
619 addDirtyWidget(widget, rgn);
620 sendUpdateRequest(tlw, updateImmediately);
624 if (widget->d_func()->inDirtyList) {
625 if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) {
626 #ifndef QT_NO_GRAPHICSEFFECT
627 if (widget->d_func()->graphicsEffect)
628 widget->d_func()->dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect());
630 #endif //QT_NO_GRAPHICSEFFECT
631 widget->d_func()->dirty += rgn;
634 addDirtyWidget(widget, rgn);
637 if (updateImmediately)
638 sendUpdateRequest(tlw, updateImmediately);
642 This function is equivalent to calling markDirty(QRegion(rect), ...), but
643 is more efficient as it eliminates QRegion operations/allocations and can
644 use the rect more precisely for additional cut-offs.
646 ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
648 void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool updateImmediately,
649 bool invalidateBuffer)
651 Q_ASSERT(tlw->d_func()->extra);
652 Q_ASSERT(tlw->d_func()->extra->topextra);
653 Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize);
654 Q_ASSERT(widget->isVisible() && widget->updatesEnabled());
655 Q_ASSERT(widget->window() == tlw);
656 Q_ASSERT(!rect.isEmpty());
658 #ifndef QT_NO_GRAPHICSEFFECT
659 widget->d_func()->invalidateGraphicsEffectsRecursively();
660 #endif //QT_NO_GRAPHICSEFFECT
662 if (widget->d_func()->paintOnScreen()) {
663 if (widget->d_func()->dirty.isEmpty()) {
664 widget->d_func()->dirty = QRegion(rect);
665 sendUpdateRequest(widget, updateImmediately);
667 } else if (qt_region_strictContains(widget->d_func()->dirty, rect)) {
668 if (updateImmediately)
669 sendUpdateRequest(widget, updateImmediately);
670 return; // Already dirty.
673 const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty();
674 widget->d_func()->dirty += rect;
675 if (!eventAlreadyPosted || updateImmediately)
676 sendUpdateRequest(widget, updateImmediately);
680 if (fullUpdatePending) {
681 if (updateImmediately)
682 sendUpdateRequest(tlw, updateImmediately);
686 if (!windowSurface->hasFeature(QWindowSurface::PartialUpdates)) {
687 fullUpdatePending = true;
688 sendUpdateRequest(tlw, updateImmediately);
692 const QRect widgetRect = widget->d_func()->effectiveRectFor(rect);
693 const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint())));
694 if (qt_region_strictContains(dirty, translatedRect)) {
695 if (updateImmediately)
696 sendUpdateRequest(tlw, updateImmediately);
697 return; // Already dirty
700 if (invalidateBuffer) {
701 const bool eventAlreadyPosted = !dirty.isEmpty();
702 dirty += translatedRect;
703 if (!eventAlreadyPosted || updateImmediately)
704 sendUpdateRequest(tlw, updateImmediately);
708 if (dirtyWidgets.isEmpty()) {
709 addDirtyWidget(widget, rect);
710 sendUpdateRequest(tlw, updateImmediately);
714 if (widget->d_func()->inDirtyList) {
715 if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect))
716 widget->d_func()->dirty += widgetRect;
718 addDirtyWidget(widget, rect);
721 if (updateImmediately)
722 sendUpdateRequest(tlw, updateImmediately);
726 Marks the \a region of the \a widget as dirty on screen. The \a region will be copied from
727 the backing store to the \a widget's native parent next time flush() is called.
729 Paint on screen widgets are ignored.
731 void QWidgetBackingStore::markDirtyOnScreen(const QRegion ®ion, QWidget *widget, const QPoint &topLevelOffset)
733 if (!widget || widget->d_func()->paintOnScreen() || region.isEmpty())
736 #if defined(Q_WS_QWS) || defined(Q_WS_MAC)
737 if (!widget->testAttribute(Qt::WA_WState_InPaintEvent))
738 dirtyOnScreen += region.translated(topLevelOffset);
744 if (!widget->testAttribute(Qt::WA_WState_InPaintEvent))
745 dirtyOnScreen += region;
750 if (!widget->internalWinId() && !widget->isWindow()) {
751 QWidget *nativeParent = widget->nativeParentWidget(); // Alien widgets with the top-level as the native parent (common case).
752 if (nativeParent == tlw) {
753 if (!widget->testAttribute(Qt::WA_WState_InPaintEvent))
754 dirtyOnScreen += region.translated(topLevelOffset);
758 // Alien widgets with native parent != tlw.
759 QWidgetPrivate *nativeParentPrivate = nativeParent->d_func();
760 if (!nativeParentPrivate->needsFlush)
761 nativeParentPrivate->needsFlush = new QRegion;
762 const QPoint nativeParentOffset = widget->mapTo(nativeParent, QPoint());
763 *nativeParentPrivate->needsFlush += region.translated(nativeParentOffset);
764 appendDirtyOnScreenWidget(nativeParent);
768 // Native child widgets.
769 QWidgetPrivate *widgetPrivate = widget->d_func();
770 if (!widgetPrivate->needsFlush)
771 widgetPrivate->needsFlush = new QRegion;
772 *widgetPrivate->needsFlush += region;
773 appendDirtyOnScreenWidget(widget);
776 void QWidgetBackingStore::removeDirtyWidget(QWidget *w)
781 dirtyWidgetsRemoveAll(w);
782 dirtyOnScreenWidgetsRemoveAll(w);
785 QWidgetPrivate *wd = w->d_func();
786 const int n = wd->children.count();
787 for (int i = 0; i < n; ++i) {
788 if (QWidget *child = qobject_cast<QWidget*>(wd->children.at(i)))
789 removeDirtyWidget(child);
793 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER)
794 bool QWidgetBackingStore::hasDirtyWindowDecoration() const
796 QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
797 if (tlwExtra && tlwExtra->qwsManager)
798 return !tlwExtra->qwsManager->d_func()->dirtyRegions.isEmpty();
802 void QWidgetBackingStore::paintWindowDecoration()
804 if (!hasDirtyWindowDecoration())
807 QDecoration &decoration = QApplication::qwsDecoration();
808 const QRect decorationRect = tlw->rect();
809 QRegion decorationRegion = decoration.region(tlw, decorationRect);
811 QWSManagerPrivate *managerPrivate = tlw->d_func()->topData()->qwsManager->d_func();
812 const bool doClipping = !managerPrivate->entireDecorationNeedsRepaint
813 && !managerPrivate->dirtyClip.isEmpty();
816 decorationRegion &= static_cast<QWSWindowSurface *>(windowSurface)->clipRegion();
817 decorationRegion &= managerPrivate->dirtyClip;
820 if (decorationRegion.isEmpty())
823 //### The QWS decorations do not always paint the pixels they promise to paint.
824 // This causes painting problems with QWSMemorySurface. Since none of the other
825 // window surfaces actually use the region, passing an empty region is a safe
828 windowSurface->beginPaint(QRegion());
830 QPaintEngine *engine = windowSurface->paintDevice()->paintEngine();
832 const QRegion oldSystemClip(engine->systemClip());
833 engine->setSystemClip(decorationRegion.translated(tlwOffset));
835 QPainter painter(windowSurface->paintDevice());
836 painter.setFont(QApplication::font());
837 painter.translate(tlwOffset);
839 const int numDirty = managerPrivate->dirtyRegions.size();
840 for (int i = 0; i < numDirty; ++i) {
841 const int area = managerPrivate->dirtyRegions.at(i);
843 QRegion clipRegion = decoration.region(tlw, decorationRect, area);
844 if (!clipRegion.isEmpty()) {
845 // Decoration styles changes the clip and assumes the old clip is non-empty,
846 // so we have to set it, but in theory it shouldn't be required.
847 painter.setClipRegion(clipRegion);
848 decoration.paint(&painter, tlw, area, managerPrivate->dirtyStates.at(i));
851 markDirtyOnScreen(decorationRegion, tlw, QPoint());
854 windowSurface->endPaint(decorationRegion);
855 managerPrivate->clearDirtyRegions();
856 engine->setSystemClip(oldSystemClip);
860 void QWidgetBackingStore::updateLists(QWidget *cur)
865 QList<QObject*> children = cur->children();
866 for (int i = 0; i < children.size(); ++i) {
867 QWidget *child = qobject_cast<QWidget*>(children.at(i));
874 if (cur->testAttribute(Qt::WA_StaticContents))
875 addStaticWidget(cur);
877 #ifdef Q_BACKINGSTORE_SUBSURFACES
878 QTLWExtra *extra = cur->d_func()->maybeTopData();
879 if (extra && extra->windowSurface && cur != tlw)
880 subSurfaces.append(extra->windowSurface);
884 QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel)
885 : tlw(topLevel), dirtyOnScreenWidgets(0), hasDirtyFromPreviousSync(false)
886 , fullUpdatePending(0)
888 windowSurface = tlw->windowSurface();
890 windowSurface = topLevel->d_func()->createDefaultWindowSurface();
892 // The QWindowSurface constructor will call QWidget::setWindowSurface(),
893 // but automatically created surfaces should not be added to the topdata.
894 #ifdef Q_BACKINGSTORE_SUBSURFACES
895 Q_ASSERT(topLevel->d_func()->topData()->windowSurface == windowSurface);
897 topLevel->d_func()->topData()->windowSurface = 0;
899 // Ensure all existing subsurfaces and static widgets are added to their respective lists.
900 updateLists(topLevel);
903 QWidgetBackingStore::~QWidgetBackingStore()
905 for (int c = 0; c < dirtyWidgets.size(); ++c) {
906 resetWidget(dirtyWidgets.at(c));
909 delete windowSurface;
911 delete dirtyOnScreenWidgets;
912 dirtyOnScreenWidgets = 0;
915 //parent's coordinates; move whole rect; update parent and widget
916 //assume the screen blt has already been done, so we don't need to refresh that part
917 void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy)
920 if (!q->isVisible() || (dx == 0 && dy == 0))
923 QWidget *tlw = q->window();
924 QTLWExtra* x = tlw->d_func()->topData();
925 if (x->inTopLevelResize)
928 static int accelEnv = -1;
929 if (accelEnv == -1) {
930 accelEnv = qgetenv("QT_NO_FAST_MOVE").toInt() == 0;
933 QWidget *pw = q->parentWidget();
934 QPoint toplevelOffset = pw->mapTo(tlw, QPoint());
935 QWidgetPrivate *pd = pw->d_func();
936 QRect clipR(pd->clipRect());
938 QWidgetBackingStore *wbs = x->backingStore.data();
939 QWSWindowSurface *surface = static_cast<QWSWindowSurface*>(wbs->windowSurface);
940 clipR = clipR.intersected(surface->clipRegion().translated(-toplevelOffset).boundingRect());
942 const QRect newRect(rect.translated(dx, dy));
943 QRect destRect = rect.intersected(clipR);
944 if (destRect.isValid())
945 destRect = destRect.translated(dx, dy).intersected(clipR);
946 const QRect sourceRect(destRect.translated(-dx, -dy));
947 const QRect parentRect(rect & clipR);
949 bool accelerateMove = accelEnv && isOpaque
950 #ifndef QT_NO_GRAPHICSVIEW
951 // No accelerate move for proxy widgets.
952 && !tlw->d_func()->extra->proxyWidget
954 && !isOverlapped(sourceRect) && !isOverlapped(destRect);
956 if (!accelerateMove) {
957 QRegion parentR(effectiveRectFor(parentRect));
958 if (!extra || !extra->hasMask) {
961 // invalidateBuffer() excludes anything outside the mask
962 parentR += newRect & clipR;
964 pd->invalidateBuffer(parentR);
965 invalidateBuffer((newRect & clipR).translated(-data.crect.topLeft()));
968 QWidgetBackingStore *wbs = x->backingStore.data();
969 QRegion childExpose(newRect & clipR);
971 if (sourceRect.isValid() && wbs->bltRect(sourceRect, dx, dy, pw))
972 childExpose -= destRect;
974 if (!pw->updatesEnabled())
977 const bool childUpdatesEnabled = q->updatesEnabled();
978 if (childUpdatesEnabled && !childExpose.isEmpty()) {
979 childExpose.translate(-data.crect.topLeft());
980 wbs->markDirty(childExpose, q);
984 QRegion parentExpose(parentRect);
985 parentExpose -= newRect;
986 if (extra && extra->hasMask)
987 parentExpose += QRegion(newRect) - extra->mask.translated(data.crect.topLeft());
989 if (!parentExpose.isEmpty()) {
990 wbs->markDirty(parentExpose, pw);
994 if (childUpdatesEnabled) {
995 QRegion needsFlush(sourceRect);
996 needsFlush += destRect;
997 wbs->markDirtyOnScreen(needsFlush, pw, toplevelOffset);
1002 //widget's coordinates; scroll within rect; only update widget
1003 void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy)
1006 QWidget *tlw = q->window();
1007 QTLWExtra* x = tlw->d_func()->topData();
1008 if (x->inTopLevelResize)
1011 QWidgetBackingStore *wbs = x->backingStore.data();
1015 static int accelEnv = -1;
1016 if (accelEnv == -1) {
1017 accelEnv = qgetenv("QT_NO_FAST_SCROLL").toInt() == 0;
1020 QRect scrollRect = rect & clipRect();
1021 bool overlapped = false;
1022 bool accelerateScroll = accelEnv && isOpaque
1023 && !(overlapped = isOverlapped(scrollRect.translated(data.crect.topLeft())));
1025 #if defined(Q_WS_QWS)
1026 QWSWindowSurface *surface;
1027 surface = static_cast<QWSWindowSurface*>(wbs->windowSurface);
1029 if (accelerateScroll && !surface->isBuffered()) {
1030 const QRegion surfaceClip = surface->clipRegion();
1031 const QRegion outsideClip = QRegion(rect) - surfaceClip;
1032 if (!outsideClip.isEmpty()) {
1033 const QVector<QRect> clipped = (surfaceClip & rect).rects();
1034 if (clipped.size() < 8) {
1035 for (int i = 0; i < clipped.size(); ++i)
1036 this->scrollRect(clipped.at(i), dx, dy);
1039 accelerateScroll = false;
1045 if (!accelerateScroll) {
1047 QRegion region(scrollRect);
1048 subtractOpaqueSiblings(region);
1049 invalidateBuffer(region);
1051 invalidateBuffer(scrollRect);
1054 const QPoint toplevelOffset = q->mapTo(tlw, QPoint());
1056 QWSWindowSurface *surface = static_cast<QWSWindowSurface*>(wbs->windowSurface);
1057 const QRegion clip = surface->clipRegion().translated(-toplevelOffset) & scrollRect;
1058 const QRect clipBoundingRect = clip.boundingRect();
1059 scrollRect &= clipBoundingRect;
1061 const QRect destRect = scrollRect.translated(dx, dy) & scrollRect;
1062 const QRect sourceRect = destRect.translated(-dx, -dy);
1064 QRegion childExpose(scrollRect);
1065 if (sourceRect.isValid()) {
1066 if (wbs->bltRect(sourceRect, dx, dy, q))
1067 childExpose -= destRect;
1071 if (rect == q->rect()) {
1072 dirty.translate(dx, dy);
1074 QRegion dirtyScrollRegion = dirty.intersected(scrollRect);
1075 if (!dirtyScrollRegion.isEmpty()) {
1076 dirty -= dirtyScrollRegion;
1077 dirtyScrollRegion.translate(dx, dy);
1078 dirty += dirtyScrollRegion;
1083 if (!q->updatesEnabled())
1086 if (!childExpose.isEmpty()) {
1087 wbs->markDirty(childExpose, q);
1091 // Instead of using native scroll-on-screen, we copy from
1092 // backingstore, giving only one screen update for each
1093 // scroll, and a solid appearance
1094 wbs->markDirtyOnScreen(destRect, q, toplevelOffset);
1098 static inline bool discardSyncRequest(QWidget *tlw, QTLWExtra *tlwExtra)
1100 if (!tlw || !tlwExtra)
1104 // Delay the sync until we get an Expose event from X11 (initial show).
1105 // Qt::WA_Mapped is set to true, but the actual mapping has not yet occurred.
1106 // However, we must repaint immediately regardless of the state if someone calls repaint().
1107 if (tlwExtra->waitingForMapNotify && !tlwExtra->inRepaint)
1111 if (!tlw->testAttribute(Qt::WA_Mapped))
1114 if (!tlw->isVisible()
1116 // If we're minimized on X11, WA_Mapped will be false and we
1117 // will return in the case above. Some window managers on X11
1118 // sends us the PropertyNotify to change the minimized state
1119 // *AFTER* we've received the expose event, which is baaad.
1120 || tlw->isMinimized()
1129 Synchronizes the \a exposedRegion of the \a exposedWidget with the backing store.
1131 If there's nothing to repaint, the area is flushed and painting does not occur;
1132 otherwise the area is marked as dirty on screen and will be flushed right after
1133 we are done with all painting.
1135 void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedRegion)
1137 QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
1138 if (discardSyncRequest(tlw, tlwExtra) || tlwExtra->inTopLevelResize)
1141 if (!exposedWidget || !exposedWidget->internalWinId() || !exposedWidget->isVisible()
1142 || !exposedWidget->updatesEnabled() || exposedRegion.isEmpty()) {
1146 // If there's no preserved contents support we always need
1147 // to do a full repaint before flushing
1148 if (!windowSurface->hasFeature(QWindowSurface::PreservedContents))
1149 fullUpdatePending = true;
1151 // Nothing to repaint.
1153 qt_flush(exposedWidget, exposedRegion, windowSurface, tlw, tlwOffset);
1157 if (exposedWidget != tlw)
1158 markDirtyOnScreen(exposedRegion, exposedWidget, exposedWidget->mapTo(tlw, QPoint()));
1160 markDirtyOnScreen(exposedRegion, exposedWidget, QPoint());
1165 Synchronizes the backing store, i.e. dirty areas are repainted and flushed.
1167 void QWidgetBackingStore::sync()
1169 QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
1170 if (discardSyncRequest(tlw, tlwExtra)) {
1171 // If the top-level is minimized, it's not visible on the screen so we can delay the
1172 // update until it's shown again. In order to do that we must keep the dirty states.
1173 // These will be cleared when we receive the first expose after showNormal().
1174 // However, if the widget is not visible (isVisible() returns false), everything will
1175 // be invalidated once the widget is shown again, so clear all dirty states.
1176 if (!tlw->isVisible()) {
1178 for (int i = 0; i < dirtyWidgets.size(); ++i)
1179 resetWidget(dirtyWidgets.at(i));
1180 dirtyWidgets.clear();
1181 fullUpdatePending = false;
1186 const bool updatesDisabled = !tlw->updatesEnabled();
1187 bool repaintAllWidgets = false;
1189 const bool inTopLevelResize = tlwExtra->inTopLevelResize;
1190 const QRect tlwRect(topLevelRect());
1192 const QRect surfaceGeometry(tlwRect.topLeft(), windowSurface->size());
1194 const QRect surfaceGeometry(windowSurface->geometry());
1196 if ((fullUpdatePending || inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) {
1197 if (hasStaticContents()) {
1198 // Repaint existing dirty area and newly visible area.
1199 const QRect clipRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height());
1200 const QRegion staticRegion(staticContents(0, clipRect));
1201 QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height());
1202 newVisible -= staticRegion;
1203 dirty += newVisible;
1204 windowSurface->setStaticContents(staticRegion);
1206 // Repaint everything.
1207 dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height());
1208 for (int i = 0; i < dirtyWidgets.size(); ++i)
1209 resetWidget(dirtyWidgets.at(i));
1210 dirtyWidgets.clear();
1211 repaintAllWidgets = true;
1216 if (inTopLevelResize || surfaceGeometry.size() != tlwRect.size())
1217 windowSurface->resize(tlwRect.size());
1219 if (inTopLevelResize || surfaceGeometry != tlwRect)
1220 windowSurface->setGeometry(tlwRect);
1223 if (updatesDisabled)
1226 if (hasDirtyFromPreviousSync)
1227 dirty += dirtyFromPreviousSync;
1229 // Contains everything that needs repaint.
1230 QRegion toClean(dirty);
1232 // Loop through all update() widgets and remove them from the list before they are
1233 // painted (in case someone calls update() in paintEvent). If the widget is opaque
1234 // and does not have transparent overlapping siblings, append it to the
1235 // opaqueNonOverlappedWidgets list and paint it directly without composition.
1236 QVarLengthArray<QWidget *, 32> opaqueNonOverlappedWidgets;
1237 for (int i = 0; i < dirtyWidgets.size(); ++i) {
1238 QWidget *w = dirtyWidgets.at(i);
1239 QWidgetPrivate *wd = w->d_func();
1240 if (wd->data.in_destructor)
1243 // Clip with mask() and clipRect().
1244 wd->dirty &= wd->clipRect();
1245 wd->clipToEffectiveMask(wd->dirty);
1247 // Subtract opaque siblings and children.
1248 bool hasDirtySiblingsAbove = false;
1249 // We know for sure that the widget isn't overlapped if 'isMoved' is true.
1251 wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove);
1252 // Scrolled and moved widgets must draw all children.
1253 if (!wd->isScrolled && !wd->isMoved)
1254 wd->subtractOpaqueChildren(wd->dirty, w->rect());
1256 if (wd->dirty.isEmpty()) {
1261 const QRegion widgetDirty(w != tlw ? wd->dirty.translated(w->mapTo(tlw, QPoint()))
1263 toClean += widgetDirty;
1265 #ifndef QT_NO_GRAPHICSVIEW
1266 if (tlw->d_func()->extra->proxyWidget) {
1272 if (!hasDirtySiblingsAbove && wd->isOpaque && !dirty.intersects(widgetDirty.boundingRect())) {
1273 opaqueNonOverlappedWidgets.append(w);
1276 dirty += widgetDirty;
1279 dirtyWidgets.clear();
1281 fullUpdatePending = false;
1283 if (toClean.isEmpty()) {
1284 // Nothing to repaint. However, we might have newly exposed areas on the
1285 // screen if this function was called from sync(QWidget *, QRegion)), so
1286 // we have to make sure those are flushed.
1291 #ifndef QT_NO_GRAPHICSVIEW
1292 if (tlw->d_func()->extra->proxyWidget) {
1293 updateStaticContentsSize();
1295 const QVector<QRect> rects(toClean.rects());
1296 for (int i = 0; i < rects.size(); ++i)
1297 tlw->d_func()->extra->proxyWidget->update(rects.at(i));
1302 #ifndef Q_BACKINGSTORE_SUBSURFACES
1303 BeginPaintInfo beginPaintInfo;
1304 beginPaint(toClean, tlw, windowSurface, &beginPaintInfo);
1305 if (beginPaintInfo.nothingToPaint) {
1306 for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i)
1307 resetWidget(opaqueNonOverlappedWidgets[i]);
1313 // Must do this before sending any paint events because
1314 // the size may change in the paint event.
1315 updateStaticContentsSize();
1316 const QRegion dirtyCopy(dirty);
1319 // Paint opaque non overlapped widgets.
1320 for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) {
1321 QWidget *w = opaqueNonOverlappedWidgets[i];
1322 QWidgetPrivate *wd = w->d_func();
1324 int flags = QWidgetPrivate::DrawRecursive;
1325 // Scrolled and moved widgets must draw all children.
1326 if (!wd->isScrolled && !wd->isMoved)
1327 flags |= QWidgetPrivate::DontDrawOpaqueChildren;
1329 flags |= QWidgetPrivate::DrawAsRoot;
1331 QRegion toBePainted(wd->dirty);
1334 #ifdef Q_BACKINGSTORE_SUBSURFACES
1335 QWindowSurface *subSurface = w->windowSurface();
1336 BeginPaintInfo beginPaintInfo;
1338 QPoint off = w->mapTo(tlw, QPoint());
1339 toBePainted.translate(off);
1340 beginPaint(toBePainted, w, subSurface, &beginPaintInfo, true);
1341 toBePainted.translate(-off);
1343 if (beginPaintInfo.nothingToPaint)
1346 if (beginPaintInfo.windowSurfaceRecreated) {
1347 // Eep the window surface has changed. The old one may have been
1348 // deleted, in which case we will segfault on the call to
1349 // painterOffset() below. Use the new window surface instead.
1350 subSurface = w->windowSurface();
1353 QPoint offset(tlwOffset);
1354 if (subSurface == windowSurface)
1355 offset += w->mapTo(tlw, QPoint());
1357 offset = static_cast<QWSWindowSurface*>(subSurface)->painterOffset();
1358 wd->drawWidget(subSurface->paintDevice(), toBePainted, offset, flags, 0, this);
1360 endPaint(toBePainted, subSurface, &beginPaintInfo);
1362 QPoint offset(tlwOffset);
1364 offset += w->mapTo(tlw, QPoint());
1365 wd->drawWidget(windowSurface->paintDevice(), toBePainted, offset, flags, 0, this);
1369 // Paint the rest with composition.
1370 #ifndef Q_BACKINGSTORE_SUBSURFACES
1371 if (repaintAllWidgets || !dirtyCopy.isEmpty()) {
1372 const int flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive;
1373 tlw->d_func()->drawWidget(windowSurface->paintDevice(), dirtyCopy, tlwOffset, flags, 0, this);
1376 endPaint(toClean, windowSurface, &beginPaintInfo);
1378 if (!repaintAllWidgets && dirtyCopy.isEmpty())
1379 return; // Nothing more to paint.
1381 QList<QWindowSurface *> surfaceList(subSurfaces);
1382 surfaceList.prepend(windowSurface);
1383 const QRect dirtyBoundingRect(dirtyCopy.boundingRect());
1385 // Loop through all window surfaces (incl. the top-level surface) and
1386 // repaint those intersecting with the bounding rect of the dirty region.
1387 for (int i = 0; i < surfaceList.size(); ++i) {
1388 QWindowSurface *subSurface = surfaceList.at(i);
1389 QWidget *w = subSurface->window();
1390 QWidgetPrivate *wd = w->d_func();
1392 const QRect clipRect = wd->clipRect().translated(w->mapTo(tlw, QPoint()));
1393 if (!qRectIntersects(dirtyBoundingRect, clipRect))
1396 toClean = dirtyCopy;
1397 BeginPaintInfo beginPaintInfo;
1398 beginPaint(toClean, w, subSurface, &beginPaintInfo);
1399 if (beginPaintInfo.nothingToPaint)
1402 if (beginPaintInfo.windowSurfaceRecreated) {
1403 // Eep the window surface has changed. The old one may have been
1404 // deleted, in which case we will segfault on the call to
1405 // painterOffset() below. Use the new window surface instead.
1406 subSurface = w->windowSurface();
1409 int flags = QWidgetPrivate::DrawRecursive;
1411 flags |= QWidgetPrivate::DrawAsRoot;
1412 const QPoint painterOffset = static_cast<QWSWindowSurface*>(subSurface)->painterOffset();
1413 wd->drawWidget(subSurface->paintDevice(), toClean, painterOffset, flags, 0, this);
1415 endPaint(toClean, subSurface, &beginPaintInfo);
1421 Flushes the contents of the backing store into the top-level widget.
1422 If the \a widget is non-zero, the content is flushed to the \a widget.
1423 If the \a surface is non-zero, the content of the \a surface is flushed.
1425 void QWidgetBackingStore::flush(QWidget *widget, QWindowSurface *surface)
1427 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER)
1428 paintWindowDecoration();
1431 if (!dirtyOnScreen.isEmpty()) {
1432 QWidget *target = widget ? widget : tlw;
1433 QWindowSurface *source = surface ? surface : windowSurface;
1434 qt_flush(target, dirtyOnScreen, source, tlw, tlwOffset);
1435 dirtyOnScreen = QRegion();
1438 if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty())
1441 for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) {
1442 QWidget *w = dirtyOnScreenWidgets->at(i);
1443 QWidgetPrivate *wd = w->d_func();
1444 Q_ASSERT(wd->needsFlush);
1445 qt_flush(w, *wd->needsFlush, windowSurface, tlw, tlwOffset);
1446 *wd->needsFlush = QRegion();
1448 dirtyOnScreenWidgets->clear();
1451 static inline bool discardInvalidateBufferRequest(QWidget *widget, QTLWExtra *tlwExtra)
1454 if (QApplication::closingDown())
1457 if (!tlwExtra || tlwExtra->inTopLevelResize || !tlwExtra->backingStore)
1460 if (!widget->isVisible() || !widget->updatesEnabled())
1467 Invalidates the buffer when the widget is resized.
1468 Static areas are never invalidated unless absolutely needed.
1470 void QWidgetPrivate::invalidateBuffer_resizeHelper(const QPoint &oldPos, const QSize &oldSize)
1473 Q_ASSERT(!q->isWindow());
1474 Q_ASSERT(q->parentWidget());
1476 const bool staticContents = q->testAttribute(Qt::WA_StaticContents);
1477 const bool sizeDecreased = (data.crect.width() < oldSize.width())
1478 || (data.crect.height() < oldSize.height());
1480 const QPoint offset(data.crect.x() - oldPos.x(), data.crect.y() - oldPos.y());
1481 const bool parentAreaExposed = !offset.isNull() || sizeDecreased;
1482 const QRect newWidgetRect(q->rect());
1483 const QRect oldWidgetRect(0, 0, oldSize.width(), oldSize.height());
1485 if (!staticContents || graphicsEffect) {
1486 QRegion staticChildren;
1487 QWidgetBackingStore *bs = 0;
1488 if (offset.isNull() && (bs = maybeBackingStore()))
1489 staticChildren = bs->staticContents(q, oldWidgetRect);
1490 const bool hasStaticChildren = !staticChildren.isEmpty();
1492 if (hasStaticChildren) {
1493 QRegion dirty(newWidgetRect);
1494 dirty -= staticChildren;
1495 invalidateBuffer(dirty);
1497 // Entire widget needs repaint.
1498 invalidateBuffer(newWidgetRect);
1501 if (!parentAreaExposed)
1504 // Invalidate newly exposed area of the parent.
1505 if (!graphicsEffect && extra && extra->hasMask) {
1506 QRegion parentExpose(extra->mask.translated(oldPos));
1507 parentExpose &= QRect(oldPos, oldSize);
1508 if (hasStaticChildren)
1509 parentExpose -= data.crect; // Offset is unchanged, safe to do this.
1510 q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
1512 if (hasStaticChildren && !graphicsEffect) {
1513 QRegion parentExpose(QRect(oldPos, oldSize));
1514 parentExpose -= data.crect; // Offset is unchanged, safe to do this.
1515 q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
1517 q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(QRect(oldPos, oldSize)));
1523 // Move static content to its new position.
1524 if (!offset.isNull()) {
1525 if (sizeDecreased) {
1526 const QSize minSize(qMin(oldSize.width(), data.crect.width()),
1527 qMin(oldSize.height(), data.crect.height()));
1528 moveRect(QRect(oldPos, minSize), offset.x(), offset.y());
1530 moveRect(QRect(oldPos, oldSize), offset.x(), offset.y());
1534 // Invalidate newly visible area of the widget.
1535 if (!sizeDecreased || !oldWidgetRect.contains(newWidgetRect)) {
1536 QRegion newVisible(newWidgetRect);
1537 newVisible -= oldWidgetRect;
1538 invalidateBuffer(newVisible);
1541 if (!parentAreaExposed)
1544 // Invalidate newly exposed area of the parent.
1545 const QRect oldRect(oldPos, oldSize);
1546 if (extra && extra->hasMask) {
1547 QRegion parentExpose(oldRect);
1548 parentExpose &= extra->mask.translated(oldPos);
1549 parentExpose -= (extra->mask.translated(data.crect.topLeft()) & data.crect);
1550 q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
1552 QRegion parentExpose(oldRect);
1553 parentExpose -= data.crect;
1554 q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
1559 Invalidates the \a rgn (in widget's coordinates) of the backing store, i.e.
1560 all widgets intersecting with the region will be repainted when the backing store
1563 ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
1565 void QWidgetPrivate::invalidateBuffer(const QRegion &rgn)
1569 QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
1570 if (discardInvalidateBufferRequest(q, tlwExtra) || rgn.isEmpty())
1575 if (!graphicsEffect && extra && extra->hasMask)
1576 wrgn &= extra->mask;
1580 tlwExtra->backingStore->markDirty(wrgn, q, false, true);
1584 This function is equivalent to calling invalidateBuffer(QRegion(rect), ...), but
1585 is more efficient as it eliminates QRegion operations/allocations and can
1586 use the rect more precisely for additional cut-offs.
1588 ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
1590 void QWidgetPrivate::invalidateBuffer(const QRect &rect)
1594 QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
1595 if (discardInvalidateBufferRequest(q, tlwExtra) || rect.isEmpty())
1599 wRect &= clipRect();
1600 if (wRect.isEmpty())
1603 if (graphicsEffect || !extra || !extra->hasMask) {
1604 tlwExtra->backingStore->markDirty(wRect, q, false, true);
1608 QRegion wRgn(extra->mask);
1613 tlwExtra->backingStore->markDirty(wRgn, q, false, true);
1616 void QWidgetPrivate::repaint_sys(const QRegion &rgn)
1618 if (data.in_destructor)
1622 if (q->testAttribute(Qt::WA_StaticContents)) {
1625 extra->staticContentsSize = data.crect.size();
1628 #ifdef Q_WS_QPA //Dont even call q->p
1629 QPaintEngine *engine = 0;
1631 QPaintEngine *engine = q->paintEngine();
1633 // QGLWidget does not support partial updates if:
1634 // 1) The context is double buffered
1635 // 2) The context is single buffered and auto-fill background is enabled.
1636 const bool noPartialUpdateSupport = (engine && (engine->type() == QPaintEngine::OpenGL
1637 || engine->type() == QPaintEngine::OpenGL2))
1638 && (usesDoubleBufferedGLContext || q->autoFillBackground());
1639 QRegion toBePainted(noPartialUpdateSupport ? q->rect() : rgn);
1642 // No difference between update() and repaint() on the Mac.
1643 update_sys(toBePainted);
1647 toBePainted &= clipRect();
1648 clipToEffectiveMask(toBePainted);
1649 if (toBePainted.isEmpty())
1650 return; // Nothing to repaint.
1652 #ifndef QT_NO_PAINT_DEBUG
1653 bool flushed = QWidgetBackingStore::flushPaint(q, toBePainted);
1656 drawWidget(q, toBePainted, QPoint(), QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawPaintOnScreen, 0);
1658 #ifndef QT_NO_PAINT_DEBUG
1660 QWidgetBackingStore::unflushPaint(q, toBePainted);
1663 if (!q->testAttribute(Qt::WA_PaintOutsidePaintEvent) && q->paintingActive())
1664 qWarning("QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent");