2c9ad14bcfe5819f6f7f85eef32d2592c6873cea
[profile/ivi/qtbase.git] / src / widgets / kernel / qwidgetbackingstore.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include "qplatformdefs.h"
44
45 #include "qwidgetbackingstore_p.h"
46
47 #include <QtCore/qglobal.h>
48 #include <QtCore/qdebug.h>
49 #include <QtCore/qvarlengtharray.h>
50 #include <QtGui/qevent.h>
51 #include <QtWidgets/qapplication.h>
52 #include <QtGui/qpaintengine.h>
53 #include <QtWidgets/qgraphicsproxywidget.h>
54
55 #include <private/qwidget_p.h>
56 #include <private/qapplication_p.h>
57 #include <private/qpaintengine_raster_p.h>
58 #include <private/qgraphicseffect_p.h>
59
60 QT_BEGIN_NAMESPACE
61
62 extern QRegion qt_dirtyRegion(QWidget *);
63
64 /*
65    A version of QRect::intersects() that does not normalize the rects.
66 */
67 static inline bool qRectIntersects(const QRect &r1, const QRect &r2)
68 {
69     return (qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right())
70             && qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom()));
71 }
72
73 /**
74  * Flushes the contents of the \a backingStore into the screen area of \a widget.
75  * \a tlwOffset is the position of the top level widget relative to the window surface.
76  * \a region is the region to be updated in \a widget coordinates.
77  */
78 static inline void qt_flush(QWidget *widget, const QRegion &region, QBackingStore *backingStore,
79                             QWidget *tlw, const QPoint &tlwOffset)
80 {
81     Q_ASSERT(widget);
82     Q_ASSERT(!region.isEmpty());
83     Q_ASSERT(backingStore);
84     Q_ASSERT(tlw);
85
86 #if !defined(QT_NO_PAINT_DEBUG)
87     static int flushUpdate = qgetenv("QT_FLUSH_UPDATE").toInt();
88     if (flushUpdate > 0)
89         QWidgetBackingStore::showYellowThing(widget, region, flushUpdate * 10, false);
90 #endif
91
92     //The performance hit by doing this should be negligible. However, be aware that
93     //using this FPS when you have > 1 windowsurface can give you inaccurate FPS
94     static bool fpsDebug = qgetenv("QT_DEBUG_FPS").toInt();
95     if (fpsDebug) {
96         static QTime time = QTime::currentTime();
97         static int frames = 0;
98
99         frames++;
100
101         if(time.elapsed() > 5000) {
102             double fps = double(frames * 1000) /time.restart();
103             fprintf(stderr,"FPS: %.1f\n",fps);
104             frames = 0;
105         }
106     }
107     if (widget != tlw)
108         backingStore->flush(region, widget->windowHandle(), tlwOffset + widget->mapTo(tlw, QPoint()));
109     else
110         backingStore->flush(region, widget->windowHandle(), tlwOffset);
111 }
112
113 #ifndef QT_NO_PAINT_DEBUG
114 #ifdef Q_WS_WIN
115 static void showYellowThing_win(QWidget *widget, const QRegion &region, int msec)
116 {
117     HBRUSH brush;
118     static int i = 0;
119     switch (i) {
120     case 0:
121         brush = CreateSolidBrush(RGB(255, 255, 0));
122         break;
123     case 1:
124         brush = CreateSolidBrush(RGB(255, 200, 55));
125         break;
126     case 2:
127         brush = CreateSolidBrush(RGB(200, 255, 55));
128         break;
129     case 3:
130         brush = CreateSolidBrush(RGB(200, 200, 0));
131         break;
132     }
133     i = (i + 1) & 3;
134
135     HDC hdc = widget->getDC();
136
137     const QVector<QRect> &rects = region.rects();
138     foreach (QRect rect, rects) {
139         RECT winRect;
140         SetRect(&winRect, rect.left(), rect.top(), rect.right(), rect.bottom());
141         FillRect(hdc, &winRect, brush);
142     }
143
144     widget->releaseDC(hdc);
145     ::Sleep(msec);
146 }
147 #endif
148
149 void QWidgetBackingStore::showYellowThing(QWidget *widget, const QRegion &toBePainted, int msec, bool unclipped)
150 {
151     QRegion paintRegion = toBePainted;
152     QRect widgetRect = widget->rect();
153
154     if (!widget->internalWinId()) {
155         QWidget *nativeParent = widget->nativeParentWidget();
156         const QPoint offset = widget->mapTo(nativeParent, QPoint(0, 0));
157         paintRegion.translate(offset);
158         widgetRect.translate(offset);
159         widget = nativeParent;
160     }
161
162 #ifdef Q_WS_WIN
163     Q_UNUSED(unclipped);
164     showYellowThing_win(widget, paintRegion, msec);
165 #else
166     //flags to fool painter
167     bool paintUnclipped = widget->testAttribute(Qt::WA_PaintUnclipped);
168     if (unclipped && !widget->d_func()->paintOnScreen())
169         widget->setAttribute(Qt::WA_PaintUnclipped);
170
171     const bool setFlag = !widget->testAttribute(Qt::WA_WState_InPaintEvent);
172     if (setFlag)
173         widget->setAttribute(Qt::WA_WState_InPaintEvent);
174
175     //setup the engine
176     QPaintEngine *pe = widget->paintEngine();
177     if (pe) {
178         pe->setSystemClip(paintRegion);
179         {
180             QPainter p(widget);
181             p.setClipRegion(paintRegion);
182             static int i = 0;
183             switch (i) {
184             case 0:
185                 p.fillRect(widgetRect, QColor(255,255,0));
186                 break;
187             case 1:
188                 p.fillRect(widgetRect, QColor(255,200,55));
189                 break;
190             case 2:
191                 p.fillRect(widgetRect, QColor(200,255,55));
192                 break;
193             case 3:
194                 p.fillRect(widgetRect, QColor(200,200,0));
195                 break;
196             }
197             i = (i+1) & 3;
198             p.end();
199         }
200     }
201
202     if (setFlag)
203         widget->setAttribute(Qt::WA_WState_InPaintEvent, false);
204
205     //restore
206     widget->setAttribute(Qt::WA_PaintUnclipped, paintUnclipped);
207
208     if (pe)
209         pe->setSystemClip(QRegion());
210
211 #if defined(Q_OS_UNIX)
212     ::usleep(1000 * msec);
213 #endif
214 #endif // Q_WS_WIN
215 }
216
217 bool QWidgetBackingStore::flushPaint(QWidget *widget, const QRegion &rgn)
218 {
219     if (!widget)
220         return false;
221
222     int delay = 0;
223     if (widget->testAttribute(Qt::WA_WState_InPaintEvent)) {
224         static int flushPaintEvent = qgetenv("QT_FLUSH_PAINT_EVENT").toInt();
225         if (!flushPaintEvent)
226             return false;
227         delay = flushPaintEvent;
228     } else {
229         static int flushPaint = qgetenv("QT_FLUSH_PAINT").toInt();
230         if (!flushPaint)
231             return false;
232         delay = flushPaint;
233     }
234
235     QWidgetBackingStore::showYellowThing(widget, rgn, delay * 10, true);
236     return true;
237 }
238
239 void QWidgetBackingStore::unflushPaint(QWidget *widget, const QRegion &rgn)
240 {
241     if (widget->d_func()->paintOnScreen() || rgn.isEmpty())
242         return;
243
244     QWidget *tlw = widget->window();
245     QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
246     if (!tlwExtra)
247         return;
248
249     const QPoint offset = widget->mapTo(tlw, QPoint());
250     qt_flush(widget, rgn, tlwExtra->backingStoreTracker->store, tlw, offset);
251 }
252 #endif // QT_NO_PAINT_DEBUG
253
254 /*
255     Moves the whole rect by (dx, dy) in widget's coordinate system.
256     Doesn't generate any updates.
257 */
258 bool QWidgetBackingStore::bltRect(const QRect &rect, int dx, int dy, QWidget *widget)
259 {
260     const QPoint pos(tlwOffset + widget->mapTo(tlw, rect.topLeft()));
261     const QRect tlwRect(QRect(pos, rect.size()));
262     if (fullUpdatePending || dirty.intersects(tlwRect))
263         return false; // We don't want to scroll junk.
264     return store->scroll(tlwRect, dx, dy);
265 }
266
267 void QWidgetBackingStore::releaseBuffer()
268 {
269     if (store)
270         store->resize(QSize());
271 }
272
273 /*!
274     Prepares the window surface to paint a\ toClean region of the \a widget and
275     updates the BeginPaintInfo struct accordingly.
276
277     The \a toClean region might be clipped by the window surface.
278 */
279 void QWidgetBackingStore::beginPaint(QRegion &toClean, QWidget *widget, QBackingStore *backingStore,
280                                      BeginPaintInfo *returnInfo, bool toCleanIsInTopLevelCoordinates)
281 {
282     Q_UNUSED(widget);
283     Q_UNUSED(toCleanIsInTopLevelCoordinates);
284
285     // Always flush repainted areas.
286     dirtyOnScreen += toClean;
287
288 #ifdef QT_NO_PAINT_DEBUG
289     backingStore->beginPaint(toClean);
290 #else
291     returnInfo->wasFlushed = QWidgetBackingStore::flushPaint(tlw, toClean);
292     // Avoid deadlock with QT_FLUSH_PAINT: the server will wait for
293     // the BackingStore lock, so if we hold that, the server will
294     // never release the Communication lock that we are waiting for in
295     // sendSynchronousCommand
296     if (!returnInfo->wasFlushed)
297         backingStore->beginPaint(toClean);
298 #endif
299
300     Q_UNUSED(returnInfo);
301 }
302
303 void QWidgetBackingStore::endPaint(const QRegion &cleaned, QBackingStore *backingStore,
304         BeginPaintInfo *beginPaintInfo)
305 {
306 #ifndef QT_NO_PAINT_DEBUG
307     if (!beginPaintInfo->wasFlushed)
308         backingStore->endPaint();
309     else
310         QWidgetBackingStore::unflushPaint(tlw, cleaned);
311 #else
312     Q_UNUSED(beginPaintInfo);
313     Q_UNUSED(cleaned);
314     backingStore->endPaint();
315 #endif
316
317     flush();
318 }
319
320 /*!
321     Returns the region (in top-level coordinates) that needs repaint and/or flush.
322
323     If the widget is non-zero, only the dirty region for the widget is returned
324     and the region will be in widget coordinates.
325 */
326 QRegion QWidgetBackingStore::dirtyRegion(QWidget *widget) const
327 {
328     const bool widgetDirty = widget && widget != tlw;
329     const QRect tlwRect(topLevelRect());
330     const QRect surfaceGeometry(tlwRect.topLeft(), store->size());
331     if (fullUpdatePending || (surfaceGeometry != tlwRect && surfaceGeometry.size() != tlwRect.size())) {
332         if (widgetDirty) {
333             const QRect dirtyTlwRect = QRect(QPoint(), tlwRect.size());
334             const QPoint offset(widget->mapTo(tlw, QPoint()));
335             const QRect dirtyWidgetRect(dirtyTlwRect & widget->rect().translated(offset));
336             return dirtyWidgetRect.translated(-offset);
337         }
338         return QRect(QPoint(), tlwRect.size());
339     }
340
341     // Calculate the region that needs repaint.
342     QRegion r(dirty);
343     for (int i = 0; i < dirtyWidgets.size(); ++i) {
344         QWidget *w = dirtyWidgets.at(i);
345         if (widgetDirty && w != widget && !widget->isAncestorOf(w))
346             continue;
347         r += w->d_func()->dirty.translated(w->mapTo(tlw, QPoint()));
348     }
349
350     // Append the region that needs flush.
351     r += dirtyOnScreen;
352
353     if (dirtyOnScreenWidgets) { // Only in use with native child widgets.
354         for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) {
355             QWidget *w = dirtyOnScreenWidgets->at(i);
356             if (widgetDirty && w != widget && !widget->isAncestorOf(w))
357                 continue;
358             QWidgetPrivate *wd = w->d_func();
359             Q_ASSERT(wd->needsFlush);
360             r += wd->needsFlush->translated(w->mapTo(tlw, QPoint()));
361         }
362     }
363
364     if (widgetDirty) {
365         // Intersect with the widget geometry and translate to its coordinates.
366         const QPoint offset(widget->mapTo(tlw, QPoint()));
367         r &= widget->rect().translated(offset);
368         r.translate(-offset);
369     }
370     return r;
371 }
372
373 /*!
374     Returns the static content inside the \a parent if non-zero; otherwise the static content
375     for the entire backing store is returned. The content will be clipped to \a withinClipRect
376     if non-empty.
377 */
378 QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &withinClipRect) const
379 {
380     if (!parent && tlw->testAttribute(Qt::WA_StaticContents)) {
381         const QSize surfaceGeometry(store->size());
382         QRect surfaceRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height());
383         if (!withinClipRect.isEmpty())
384             surfaceRect &= withinClipRect;
385         return QRegion(surfaceRect);
386     }
387
388     QRegion region;
389     if (parent && parent->d_func()->children.isEmpty())
390         return region;
391
392     const bool clipToRect = !withinClipRect.isEmpty();
393     const int count = staticWidgets.count();
394     for (int i = 0; i < count; ++i) {
395         QWidget *w = staticWidgets.at(i);
396         QWidgetPrivate *wd = w->d_func();
397         if (!wd->isOpaque || !wd->extra || wd->extra->staticContentsSize.isEmpty()
398             || !w->isVisible() || (parent && !parent->isAncestorOf(w))) {
399             continue;
400         }
401
402         QRect rect(0, 0, wd->extra->staticContentsSize.width(), wd->extra->staticContentsSize.height());
403         const QPoint offset = w->mapTo(parent ? parent : tlw, QPoint());
404         if (clipToRect)
405             rect &= withinClipRect.translated(-offset);
406         if (rect.isEmpty())
407             continue;
408
409         rect &= wd->clipRect();
410         if (rect.isEmpty())
411             continue;
412
413         QRegion visible(rect);
414         wd->clipToEffectiveMask(visible);
415         if (visible.isEmpty())
416             continue;
417         wd->subtractOpaqueSiblings(visible, 0, /*alsoNonOpaque=*/true);
418
419         visible.translate(offset);
420         region += visible;
421     }
422
423     return region;
424 }
425
426 static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately)
427 {
428     if (!widget)
429         return;
430
431     if (updateImmediately) {
432         QEvent event(QEvent::UpdateRequest);
433         QApplication::sendEvent(widget, &event);
434     } else {
435         QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
436     }
437 }
438
439 /*!
440     Marks the region of the widget as dirty (if not already marked as dirty) and
441     posts an UpdateRequest event to the top-level widget (if not already posted).
442
443     If updateImmediately is true, the event is sent immediately instead of posted.
444
445     If invalidateBuffer is true, all widgets intersecting with the region will be dirty.
446
447     If the widget paints directly on screen, the event is sent to the widget
448     instead of the top-level widget, and invalidateBuffer is completely ignored.
449
450     ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
451 */
452 void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool updateImmediately,
453                                     bool invalidateBuffer)
454 {
455     Q_ASSERT(tlw->d_func()->extra);
456     Q_ASSERT(tlw->d_func()->extra->topextra);
457     Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize);
458     Q_ASSERT(widget->isVisible() && widget->updatesEnabled());
459     Q_ASSERT(widget->window() == tlw);
460     Q_ASSERT(!rgn.isEmpty());
461
462 #ifndef QT_NO_GRAPHICSEFFECT
463     widget->d_func()->invalidateGraphicsEffectsRecursively();
464 #endif //QT_NO_GRAPHICSEFFECT
465
466     if (widget->d_func()->paintOnScreen()) {
467         if (widget->d_func()->dirty.isEmpty()) {
468             widget->d_func()->dirty = rgn;
469             sendUpdateRequest(widget, updateImmediately);
470             return;
471         } else if (qt_region_strictContains(widget->d_func()->dirty, widget->rect())) {
472             if (updateImmediately)
473                 sendUpdateRequest(widget, updateImmediately);
474             return; // Already dirty.
475         }
476
477         const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty();
478         widget->d_func()->dirty += rgn;
479         if (!eventAlreadyPosted || updateImmediately)
480             sendUpdateRequest(widget, updateImmediately);
481         return;
482     }
483
484     if (fullUpdatePending) {
485         if (updateImmediately)
486             sendUpdateRequest(tlw, updateImmediately);
487         return;
488     }
489
490     const QPoint offset = widget->mapTo(tlw, QPoint());
491     const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect());
492     if (qt_region_strictContains(dirty, widgetRect.translated(offset))) {
493         if (updateImmediately)
494             sendUpdateRequest(tlw, updateImmediately);
495         return; // Already dirty.
496     }
497
498     if (invalidateBuffer) {
499         const bool eventAlreadyPosted = !dirty.isEmpty();
500 #ifndef QT_NO_GRAPHICSEFFECT
501         if (widget->d_func()->graphicsEffect)
502             dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset);
503         else
504 #endif //QT_NO_GRAPHICSEFFECT
505             dirty += rgn.translated(offset);
506         if (!eventAlreadyPosted || updateImmediately)
507             sendUpdateRequest(tlw, updateImmediately);
508         return;
509     }
510
511     if (dirtyWidgets.isEmpty()) {
512         addDirtyWidget(widget, rgn);
513         sendUpdateRequest(tlw, updateImmediately);
514         return;
515     }
516
517     if (widget->d_func()->inDirtyList) {
518         if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) {
519 #ifndef QT_NO_GRAPHICSEFFECT
520             if (widget->d_func()->graphicsEffect)
521                 widget->d_func()->dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect());
522             else
523 #endif //QT_NO_GRAPHICSEFFECT
524                 widget->d_func()->dirty += rgn;
525         }
526     } else {
527         addDirtyWidget(widget, rgn);
528     }
529
530     if (updateImmediately)
531         sendUpdateRequest(tlw, updateImmediately);
532 }
533
534 /*!
535     This function is equivalent to calling markDirty(QRegion(rect), ...), but
536     is more efficient as it eliminates QRegion operations/allocations and can
537     use the rect more precisely for additional cut-offs.
538
539     ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
540 */
541 void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool updateImmediately,
542                                     bool invalidateBuffer)
543 {
544     Q_ASSERT(tlw->d_func()->extra);
545     Q_ASSERT(tlw->d_func()->extra->topextra);
546     Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize);
547     Q_ASSERT(widget->isVisible() && widget->updatesEnabled());
548     Q_ASSERT(widget->window() == tlw);
549     Q_ASSERT(!rect.isEmpty());
550
551 #ifndef QT_NO_GRAPHICSEFFECT
552     widget->d_func()->invalidateGraphicsEffectsRecursively();
553 #endif //QT_NO_GRAPHICSEFFECT
554
555     if (widget->d_func()->paintOnScreen()) {
556         if (widget->d_func()->dirty.isEmpty()) {
557             widget->d_func()->dirty = QRegion(rect);
558             sendUpdateRequest(widget, updateImmediately);
559             return;
560         } else if (qt_region_strictContains(widget->d_func()->dirty, rect)) {
561             if (updateImmediately)
562                 sendUpdateRequest(widget, updateImmediately);
563             return; // Already dirty.
564         }
565
566         const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty();
567         widget->d_func()->dirty += rect;
568         if (!eventAlreadyPosted || updateImmediately)
569             sendUpdateRequest(widget, updateImmediately);
570         return;
571     }
572
573     if (fullUpdatePending) {
574         if (updateImmediately)
575             sendUpdateRequest(tlw, updateImmediately);
576         return;
577     }
578
579     const QRect widgetRect = widget->d_func()->effectiveRectFor(rect);
580     const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint())));
581     if (qt_region_strictContains(dirty, translatedRect)) {
582         if (updateImmediately)
583             sendUpdateRequest(tlw, updateImmediately);
584         return; // Already dirty
585     }
586
587     if (invalidateBuffer) {
588         const bool eventAlreadyPosted = !dirty.isEmpty();
589         dirty += translatedRect;
590         if (!eventAlreadyPosted || updateImmediately)
591             sendUpdateRequest(tlw, updateImmediately);
592         return;
593     }
594
595     if (dirtyWidgets.isEmpty()) {
596         addDirtyWidget(widget, rect);
597         sendUpdateRequest(tlw, updateImmediately);
598         return;
599     }
600
601     if (widget->d_func()->inDirtyList) {
602         if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect))
603             widget->d_func()->dirty += widgetRect;
604     } else {
605         addDirtyWidget(widget, rect);
606     }
607
608     if (updateImmediately)
609         sendUpdateRequest(tlw, updateImmediately);
610 }
611
612 /*!
613     Marks the \a region of the \a widget as dirty on screen. The \a region will be copied from
614     the backing store to the \a widget's native parent next time flush() is called.
615
616     Paint on screen widgets are ignored.
617 */
618 void QWidgetBackingStore::markDirtyOnScreen(const QRegion &region, QWidget *widget, const QPoint &topLevelOffset)
619 {
620     if (!widget || widget->d_func()->paintOnScreen() || region.isEmpty())
621         return;
622
623 #if defined(Q_WS_MAC)
624     if (!widget->testAttribute(Qt::WA_WState_InPaintEvent))
625         dirtyOnScreen += region.translated(topLevelOffset);
626     return;
627 #endif
628
629     // Top-level.
630     if (widget == tlw) {
631         if (!widget->testAttribute(Qt::WA_WState_InPaintEvent))
632             dirtyOnScreen += region;
633         return;
634     }
635
636     // Alien widgets.
637     if (!widget->internalWinId() && !widget->isWindow()) {
638         QWidget *nativeParent = widget->nativeParentWidget();        // Alien widgets with the top-level as the native parent (common case).
639         if (nativeParent == tlw) {
640             if (!widget->testAttribute(Qt::WA_WState_InPaintEvent))
641                 dirtyOnScreen += region.translated(topLevelOffset);
642             return;
643         }
644
645         // Alien widgets with native parent != tlw.
646         QWidgetPrivate *nativeParentPrivate = nativeParent->d_func();
647         if (!nativeParentPrivate->needsFlush)
648             nativeParentPrivate->needsFlush = new QRegion;
649         const QPoint nativeParentOffset = widget->mapTo(nativeParent, QPoint());
650         *nativeParentPrivate->needsFlush += region.translated(nativeParentOffset);
651         appendDirtyOnScreenWidget(nativeParent);
652         return;
653     }
654
655     // Native child widgets.
656     QWidgetPrivate *widgetPrivate = widget->d_func();
657     if (!widgetPrivate->needsFlush)
658         widgetPrivate->needsFlush = new QRegion;
659     *widgetPrivate->needsFlush += region;
660     appendDirtyOnScreenWidget(widget);
661 }
662
663 void QWidgetBackingStore::removeDirtyWidget(QWidget *w)
664 {
665     if (!w)
666         return;
667
668     dirtyWidgetsRemoveAll(w);
669     dirtyOnScreenWidgetsRemoveAll(w);
670     resetWidget(w);
671
672     QWidgetPrivate *wd = w->d_func();
673     const int n = wd->children.count();
674     for (int i = 0; i < n; ++i) {
675         if (QWidget *child = qobject_cast<QWidget*>(wd->children.at(i)))
676             removeDirtyWidget(child);
677     }
678 }
679
680 void QWidgetBackingStore::updateLists(QWidget *cur)
681 {
682     if (!cur)
683         return;
684
685     QList<QObject*> children = cur->children();
686     for (int i = 0; i < children.size(); ++i) {
687         QWidget *child = qobject_cast<QWidget*>(children.at(i));
688         if (!child)
689             continue;
690
691         updateLists(child);
692     }
693
694     if (cur->testAttribute(Qt::WA_StaticContents))
695         addStaticWidget(cur);
696 }
697
698 QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel)
699     : tlw(topLevel), dirtyOnScreenWidgets(0), fullUpdatePending(0)
700 {
701     store = tlw->backingStore();
702     Q_ASSERT(store);
703
704     // Ensure all existing subsurfaces and static widgets are added to their respective lists.
705     updateLists(topLevel);
706 }
707
708 QWidgetBackingStore::~QWidgetBackingStore()
709 {
710     for (int c = 0; c < dirtyWidgets.size(); ++c) {
711         resetWidget(dirtyWidgets.at(c));
712     }
713
714     delete dirtyOnScreenWidgets;
715     dirtyOnScreenWidgets = 0;
716 }
717
718 //parent's coordinates; move whole rect; update parent and widget
719 //assume the screen blt has already been done, so we don't need to refresh that part
720 void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy)
721 {
722     Q_Q(QWidget);
723     if (!q->isVisible() || (dx == 0 && dy == 0))
724         return;
725
726     QWidget *tlw = q->window();
727     QTLWExtra* x = tlw->d_func()->topData();
728     if (x->inTopLevelResize)
729         return;
730
731     static int accelEnv = -1;
732     if (accelEnv == -1) {
733         accelEnv = qgetenv("QT_NO_FAST_MOVE").toInt() == 0;
734     }
735
736     QWidget *pw = q->parentWidget();
737     QPoint toplevelOffset = pw->mapTo(tlw, QPoint());
738     QWidgetPrivate *pd = pw->d_func();
739     QRect clipR(pd->clipRect());
740     const QRect newRect(rect.translated(dx, dy));
741     QRect destRect = rect.intersected(clipR);
742     if (destRect.isValid())
743         destRect = destRect.translated(dx, dy).intersected(clipR);
744     const QRect sourceRect(destRect.translated(-dx, -dy));
745     const QRect parentRect(rect & clipR);
746
747     bool accelerateMove = accelEnv && isOpaque
748 #ifndef QT_NO_GRAPHICSVIEW
749                           // No accelerate move for proxy widgets.
750                           && !tlw->d_func()->extra->proxyWidget
751 #endif
752                           && !isOverlapped(sourceRect) && !isOverlapped(destRect);
753
754     if (!accelerateMove) {
755         QRegion parentR(effectiveRectFor(parentRect));
756         if (!extra || !extra->hasMask) {
757             parentR -= newRect;
758         } else {
759             // invalidateBuffer() excludes anything outside the mask
760             parentR += newRect & clipR;
761         }
762         pd->invalidateBuffer(parentR);
763         invalidateBuffer((newRect & clipR).translated(-data.crect.topLeft()));
764     } else {
765
766         QWidgetBackingStore *wbs = x->backingStoreTracker.data();
767         QRegion childExpose(newRect & clipR);
768
769         if (sourceRect.isValid() && wbs->bltRect(sourceRect, dx, dy, pw))
770             childExpose -= destRect;
771
772         if (!pw->updatesEnabled())
773             return;
774
775         const bool childUpdatesEnabled = q->updatesEnabled();
776         if (childUpdatesEnabled && !childExpose.isEmpty()) {
777             childExpose.translate(-data.crect.topLeft());
778             wbs->markDirty(childExpose, q);
779             isMoved = true;
780         }
781
782         QRegion parentExpose(parentRect);
783         parentExpose -= newRect;
784         if (extra && extra->hasMask)
785             parentExpose += QRegion(newRect) - extra->mask.translated(data.crect.topLeft());
786
787         if (!parentExpose.isEmpty()) {
788             wbs->markDirty(parentExpose, pw);
789             pd->isMoved = true;
790         }
791
792         if (childUpdatesEnabled) {
793             QRegion needsFlush(sourceRect);
794             needsFlush += destRect;
795             wbs->markDirtyOnScreen(needsFlush, pw, toplevelOffset);
796         }
797     }
798 }
799
800 //widget's coordinates; scroll within rect;  only update widget
801 void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy)
802 {
803     Q_Q(QWidget);
804     QWidget *tlw = q->window();
805     QTLWExtra* x = tlw->d_func()->topData();
806     if (x->inTopLevelResize)
807         return;
808
809     QWidgetBackingStore *wbs = x->backingStoreTracker.data();
810     if (!wbs)
811         return;
812
813     static int accelEnv = -1;
814     if (accelEnv == -1) {
815         accelEnv = qgetenv("QT_NO_FAST_SCROLL").toInt() == 0;
816     }
817
818     QRect scrollRect = rect & clipRect();
819     bool overlapped = false;
820     bool accelerateScroll = accelEnv && isOpaque
821                             && !(overlapped = isOverlapped(scrollRect.translated(data.crect.topLeft())));
822
823     if (!accelerateScroll) {
824         if (overlapped) {
825             QRegion region(scrollRect);
826             subtractOpaqueSiblings(region);
827             invalidateBuffer(region);
828         }else {
829             invalidateBuffer(scrollRect);
830         }
831     } else {
832         const QPoint toplevelOffset = q->mapTo(tlw, QPoint());
833         const QRect destRect = scrollRect.translated(dx, dy) & scrollRect;
834         const QRect sourceRect = destRect.translated(-dx, -dy);
835
836         QRegion childExpose(scrollRect);
837         if (sourceRect.isValid()) {
838             if (wbs->bltRect(sourceRect, dx, dy, q))
839                 childExpose -= destRect;
840         }
841
842         if (inDirtyList) {
843             if (rect == q->rect()) {
844                 dirty.translate(dx, dy);
845             } else {
846                 QRegion dirtyScrollRegion = dirty.intersected(scrollRect);
847                 if (!dirtyScrollRegion.isEmpty()) {
848                     dirty -= dirtyScrollRegion;
849                     dirtyScrollRegion.translate(dx, dy);
850                     dirty += dirtyScrollRegion;
851                 }
852             }
853         }
854
855         if (!q->updatesEnabled())
856             return;
857
858         if (!childExpose.isEmpty()) {
859             wbs->markDirty(childExpose, q);
860             isScrolled = true;
861         }
862
863         // Instead of using native scroll-on-screen, we copy from
864         // backingstore, giving only one screen update for each
865         // scroll, and a solid appearance
866         wbs->markDirtyOnScreen(destRect, q, toplevelOffset);
867     }
868 }
869
870 static inline bool discardSyncRequest(QWidget *tlw, QTLWExtra *tlwExtra)
871 {
872     if (!tlw || !tlwExtra || !tlw->testAttribute(Qt::WA_Mapped) || !tlw->isVisible())
873         return true;
874
875     return false;
876 }
877
878 /*!
879     Synchronizes the \a exposedRegion of the \a exposedWidget with the backing store.
880
881     If there's nothing to repaint, the area is flushed and painting does not occur;
882     otherwise the area is marked as dirty on screen and will be flushed right after
883     we are done with all painting.
884 */
885 void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedRegion)
886 {
887     QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
888     if (discardSyncRequest(tlw, tlwExtra) || tlwExtra->inTopLevelResize)
889         return;
890
891     if (!exposedWidget || !exposedWidget->internalWinId() || !exposedWidget->isVisible()
892         || !exposedWidget->updatesEnabled() || exposedRegion.isEmpty()) {
893         return;
894     }
895
896     // Nothing to repaint.
897     if (!isDirty()) {
898         qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset);
899         return;
900     }
901
902     if (exposedWidget != tlw)
903         markDirtyOnScreen(exposedRegion, exposedWidget, exposedWidget->mapTo(tlw, QPoint()));
904     else
905         markDirtyOnScreen(exposedRegion, exposedWidget, QPoint());
906     sync();
907 }
908
909 /*!
910     Synchronizes the backing store, i.e. dirty areas are repainted and flushed.
911 */
912 void QWidgetBackingStore::sync()
913 {
914     QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
915     if (discardSyncRequest(tlw, tlwExtra)) {
916         // If the top-level is minimized, it's not visible on the screen so we can delay the
917         // update until it's shown again. In order to do that we must keep the dirty states.
918         // These will be cleared when we receive the first expose after showNormal().
919         // However, if the widget is not visible (isVisible() returns false), everything will
920         // be invalidated once the widget is shown again, so clear all dirty states.
921         if (!tlw->isVisible()) {
922             dirty = QRegion();
923             for (int i = 0; i < dirtyWidgets.size(); ++i)
924                 resetWidget(dirtyWidgets.at(i));
925             dirtyWidgets.clear();
926             fullUpdatePending = false;
927         }
928         return;
929     }
930
931     const bool updatesDisabled = !tlw->updatesEnabled();
932     bool repaintAllWidgets = false;
933
934     const bool inTopLevelResize = tlwExtra->inTopLevelResize;
935     const QRect tlwRect(topLevelRect());
936     const QRect surfaceGeometry(tlwRect.topLeft(), store->size());
937     if ((fullUpdatePending || inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) {
938         if (hasStaticContents()) {
939             // Repaint existing dirty area and newly visible area.
940             const QRect clipRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height());
941             const QRegion staticRegion(staticContents(0, clipRect));
942             QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height());
943             newVisible -= staticRegion;
944             dirty += newVisible;
945             store->setStaticContents(staticRegion);
946         } else {
947             // Repaint everything.
948             dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height());
949             for (int i = 0; i < dirtyWidgets.size(); ++i)
950                 resetWidget(dirtyWidgets.at(i));
951             dirtyWidgets.clear();
952             repaintAllWidgets = true;
953         }
954     }
955
956     if (inTopLevelResize || surfaceGeometry.size() != tlwRect.size())
957         store->resize(tlwRect.size());
958
959     if (updatesDisabled)
960         return;
961
962     // Contains everything that needs repaint.
963     QRegion toClean(dirty);
964
965     // Loop through all update() widgets and remove them from the list before they are
966     // painted (in case someone calls update() in paintEvent). If the widget is opaque
967     // and does not have transparent overlapping siblings, append it to the
968     // opaqueNonOverlappedWidgets list and paint it directly without composition.
969     QVarLengthArray<QWidget *, 32> opaqueNonOverlappedWidgets;
970     for (int i = 0; i < dirtyWidgets.size(); ++i) {
971         QWidget *w = dirtyWidgets.at(i);
972         QWidgetPrivate *wd = w->d_func();
973         if (wd->data.in_destructor)
974             continue;
975
976         // Clip with mask() and clipRect().
977         wd->dirty &= wd->clipRect();
978         wd->clipToEffectiveMask(wd->dirty);
979
980         // Subtract opaque siblings and children.
981         bool hasDirtySiblingsAbove = false;
982         // We know for sure that the widget isn't overlapped if 'isMoved' is true.
983         if (!wd->isMoved)
984             wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove);
985         // Scrolled and moved widgets must draw all children.
986         if (!wd->isScrolled && !wd->isMoved)
987             wd->subtractOpaqueChildren(wd->dirty, w->rect());
988
989         if (wd->dirty.isEmpty()) {
990             resetWidget(w);
991             continue;
992         }
993
994         const QRegion widgetDirty(w != tlw ? wd->dirty.translated(w->mapTo(tlw, QPoint()))
995                                            : wd->dirty);
996         toClean += widgetDirty;
997
998 #ifndef QT_NO_GRAPHICSVIEW
999         if (tlw->d_func()->extra->proxyWidget) {
1000             resetWidget(w);
1001             continue;
1002         }
1003 #endif
1004
1005         if (!hasDirtySiblingsAbove && wd->isOpaque && !dirty.intersects(widgetDirty.boundingRect())) {
1006             opaqueNonOverlappedWidgets.append(w);
1007         } else {
1008             resetWidget(w);
1009             dirty += widgetDirty;
1010         }
1011     }
1012     dirtyWidgets.clear();
1013
1014     fullUpdatePending = false;
1015
1016     if (toClean.isEmpty()) {
1017         // Nothing to repaint. However, we might have newly exposed areas on the
1018         // screen if this function was called from sync(QWidget *, QRegion)), so
1019         // we have to make sure those are flushed.
1020         flush();
1021         return;
1022     }
1023
1024 #ifndef QT_NO_GRAPHICSVIEW
1025     if (tlw->d_func()->extra->proxyWidget) {
1026         updateStaticContentsSize();
1027         dirty = QRegion();
1028         const QVector<QRect> rects(toClean.rects());
1029         for (int i = 0; i < rects.size(); ++i)
1030             tlw->d_func()->extra->proxyWidget->update(rects.at(i));
1031         return;
1032     }
1033 #endif
1034
1035     BeginPaintInfo beginPaintInfo;
1036     beginPaint(toClean, tlw, store, &beginPaintInfo);
1037     if (beginPaintInfo.nothingToPaint) {
1038         for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i)
1039             resetWidget(opaqueNonOverlappedWidgets[i]);
1040         dirty = QRegion();
1041         return;
1042     }
1043
1044     // Must do this before sending any paint events because
1045     // the size may change in the paint event.
1046     updateStaticContentsSize();
1047     const QRegion dirtyCopy(dirty);
1048     dirty = QRegion();
1049
1050     // Paint opaque non overlapped widgets.
1051     for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) {
1052         QWidget *w = opaqueNonOverlappedWidgets[i];
1053         QWidgetPrivate *wd = w->d_func();
1054
1055         int flags = QWidgetPrivate::DrawRecursive;
1056         // Scrolled and moved widgets must draw all children.
1057         if (!wd->isScrolled && !wd->isMoved)
1058             flags |= QWidgetPrivate::DontDrawOpaqueChildren;
1059         if (w == tlw)
1060             flags |= QWidgetPrivate::DrawAsRoot;
1061
1062         QRegion toBePainted(wd->dirty);
1063         resetWidget(w);
1064
1065         QPoint offset(tlwOffset);
1066         if (w != tlw)
1067             offset += w->mapTo(tlw, QPoint());
1068         wd->drawWidget(store->paintDevice(), toBePainted, offset, flags, 0, this);
1069     }
1070
1071     // Paint the rest with composition.
1072     if (repaintAllWidgets || !dirtyCopy.isEmpty()) {
1073         const int flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive;
1074         tlw->d_func()->drawWidget(store->paintDevice(), dirtyCopy, tlwOffset, flags, 0, this);
1075     }
1076
1077     endPaint(toClean, store, &beginPaintInfo);
1078 }
1079
1080 /*!
1081     Flushes the contents of the backing store into the top-level widget.
1082     If the \a widget is non-zero, the content is flushed to the \a widget.
1083     If the \a surface is non-zero, the content of the \a surface is flushed.
1084 */
1085 void QWidgetBackingStore::flush(QWidget *widget, QBackingStore *backingStore)
1086 {
1087     if (!dirtyOnScreen.isEmpty()) {
1088         QWidget *target = widget ? widget : tlw;
1089         QBackingStore *source = store ? store : backingStore;
1090         qt_flush(target, dirtyOnScreen, source, tlw, tlwOffset);
1091         dirtyOnScreen = QRegion();
1092     }
1093
1094     if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty())
1095         return;
1096
1097     for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) {
1098         QWidget *w = dirtyOnScreenWidgets->at(i);
1099         QWidgetPrivate *wd = w->d_func();
1100         Q_ASSERT(wd->needsFlush);
1101         qt_flush(w, *wd->needsFlush, backingStore, tlw, tlwOffset);
1102         *wd->needsFlush = QRegion();
1103     }
1104     dirtyOnScreenWidgets->clear();
1105 }
1106
1107 static inline bool discardInvalidateBufferRequest(QWidget *widget, QTLWExtra *tlwExtra)
1108 {
1109     Q_ASSERT(widget);
1110     if (QApplication::closingDown())
1111         return true;
1112
1113     if (!tlwExtra || tlwExtra->inTopLevelResize || !tlwExtra->backingStore)
1114         return true;
1115
1116     if (!widget->isVisible() || !widget->updatesEnabled())
1117         return true;
1118
1119     return false;
1120 }
1121
1122 /*!
1123     Invalidates the buffer when the widget is resized.
1124     Static areas are never invalidated unless absolutely needed.
1125 */
1126 void QWidgetPrivate::invalidateBuffer_resizeHelper(const QPoint &oldPos, const QSize &oldSize)
1127 {
1128     Q_Q(QWidget);
1129     Q_ASSERT(!q->isWindow());
1130     Q_ASSERT(q->parentWidget());
1131
1132     const bool staticContents = q->testAttribute(Qt::WA_StaticContents);
1133     const bool sizeDecreased = (data.crect.width() < oldSize.width())
1134                                || (data.crect.height() < oldSize.height());
1135
1136     const QPoint offset(data.crect.x() - oldPos.x(), data.crect.y() - oldPos.y());
1137     const bool parentAreaExposed = !offset.isNull() || sizeDecreased;
1138     const QRect newWidgetRect(q->rect());
1139     const QRect oldWidgetRect(0, 0, oldSize.width(), oldSize.height());
1140
1141     if (!staticContents || graphicsEffect) {
1142         QRegion staticChildren;
1143         QWidgetBackingStore *bs = 0;
1144         if (offset.isNull() && (bs = maybeBackingStore()))
1145             staticChildren = bs->staticContents(q, oldWidgetRect);
1146         const bool hasStaticChildren = !staticChildren.isEmpty();
1147
1148         if (hasStaticChildren) {
1149             QRegion dirty(newWidgetRect);
1150             dirty -= staticChildren;
1151             invalidateBuffer(dirty);
1152         } else {
1153             // Entire widget needs repaint.
1154             invalidateBuffer(newWidgetRect);
1155         }
1156
1157         if (!parentAreaExposed)
1158             return;
1159
1160         // Invalidate newly exposed area of the parent.
1161         if (!graphicsEffect && extra && extra->hasMask) {
1162             QRegion parentExpose(extra->mask.translated(oldPos));
1163             parentExpose &= QRect(oldPos, oldSize);
1164             if (hasStaticChildren)
1165                 parentExpose -= data.crect; // Offset is unchanged, safe to do this.
1166             q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
1167         } else {
1168             if (hasStaticChildren && !graphicsEffect) {
1169                 QRegion parentExpose(QRect(oldPos, oldSize));
1170                 parentExpose -= data.crect; // Offset is unchanged, safe to do this.
1171                 q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
1172             } else {
1173                 q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(QRect(oldPos, oldSize)));
1174             }
1175         }
1176         return;
1177     }
1178
1179     // Move static content to its new position.
1180     if (!offset.isNull()) {
1181         if (sizeDecreased) {
1182             const QSize minSize(qMin(oldSize.width(), data.crect.width()),
1183                                 qMin(oldSize.height(), data.crect.height()));
1184             moveRect(QRect(oldPos, minSize), offset.x(), offset.y());
1185         } else {
1186             moveRect(QRect(oldPos, oldSize), offset.x(), offset.y());
1187         }
1188     }
1189
1190     // Invalidate newly visible area of the widget.
1191     if (!sizeDecreased || !oldWidgetRect.contains(newWidgetRect)) {
1192         QRegion newVisible(newWidgetRect);
1193         newVisible -= oldWidgetRect;
1194         invalidateBuffer(newVisible);
1195     }
1196
1197     if (!parentAreaExposed)
1198         return;
1199
1200     // Invalidate newly exposed area of the parent.
1201     const QRect oldRect(oldPos, oldSize);
1202     if (extra && extra->hasMask) {
1203         QRegion parentExpose(oldRect);
1204         parentExpose &= extra->mask.translated(oldPos);
1205         parentExpose -= (extra->mask.translated(data.crect.topLeft()) & data.crect);
1206         q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
1207     } else {
1208         QRegion parentExpose(oldRect);
1209         parentExpose -= data.crect;
1210         q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
1211     }
1212 }
1213
1214 /*!
1215     Invalidates the \a rgn (in widget's coordinates) of the backing store, i.e.
1216     all widgets intersecting with the region will be repainted when the backing store
1217     is synced.
1218
1219     ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
1220 */
1221 void QWidgetPrivate::invalidateBuffer(const QRegion &rgn)
1222 {
1223     Q_Q(QWidget);
1224
1225     QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
1226     if (discardInvalidateBufferRequest(q, tlwExtra) || rgn.isEmpty())
1227         return;
1228
1229     QRegion wrgn(rgn);
1230     wrgn &= clipRect();
1231     if (!graphicsEffect && extra && extra->hasMask)
1232         wrgn &= extra->mask;
1233     if (wrgn.isEmpty())
1234         return;
1235
1236     tlwExtra->backingStoreTracker->markDirty(wrgn, q, false, true);
1237 }
1238
1239 /*!
1240     This function is equivalent to calling invalidateBuffer(QRegion(rect), ...), but
1241     is more efficient as it eliminates QRegion operations/allocations and can
1242     use the rect more precisely for additional cut-offs.
1243
1244     ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
1245 */
1246 void QWidgetPrivate::invalidateBuffer(const QRect &rect)
1247 {
1248     Q_Q(QWidget);
1249
1250     QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
1251     if (discardInvalidateBufferRequest(q, tlwExtra) || rect.isEmpty())
1252         return;
1253
1254     QRect wRect(rect);
1255     wRect &= clipRect();
1256     if (wRect.isEmpty())
1257         return;
1258
1259     if (graphicsEffect || !extra || !extra->hasMask) {
1260         tlwExtra->backingStoreTracker->markDirty(wRect, q, false, true);
1261         return;
1262     }
1263
1264     QRegion wRgn(extra->mask);
1265     wRgn &= wRect;
1266     if (wRgn.isEmpty())
1267         return;
1268
1269     tlwExtra->backingStoreTracker->markDirty(wRgn, q, false, true);
1270 }
1271
1272 void QWidgetPrivate::repaint_sys(const QRegion &rgn)
1273 {
1274     if (data.in_destructor)
1275         return;
1276
1277     Q_Q(QWidget);
1278     if (discardSyncRequest(q, maybeTopData()))
1279         return;
1280
1281     if (q->testAttribute(Qt::WA_StaticContents)) {
1282         if (!extra)
1283             createExtra();
1284         extra->staticContentsSize = data.crect.size();
1285     }
1286
1287     QPaintEngine *engine = q->paintEngine();
1288
1289     // QGLWidget does not support partial updates if:
1290     // 1) The context is double buffered
1291     // 2) The context is single buffered and auto-fill background is enabled.
1292     const bool noPartialUpdateSupport = (engine && (engine->type() == QPaintEngine::OpenGL
1293                                                 || engine->type() == QPaintEngine::OpenGL2))
1294                                         && (usesDoubleBufferedGLContext || q->autoFillBackground());
1295     QRegion toBePainted(noPartialUpdateSupport ? q->rect() : rgn);
1296
1297 #ifdef Q_WS_MAC
1298     // No difference between update() and repaint() on the Mac.
1299     update_sys(toBePainted);
1300     return;
1301 #endif
1302
1303     toBePainted &= clipRect();
1304     clipToEffectiveMask(toBePainted);
1305     if (toBePainted.isEmpty())
1306         return; // Nothing to repaint.
1307
1308 #ifndef QT_NO_PAINT_DEBUG
1309     bool flushed = QWidgetBackingStore::flushPaint(q, toBePainted);
1310 #endif
1311
1312     drawWidget(q, toBePainted, QPoint(), QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawPaintOnScreen, 0);
1313
1314 #ifndef QT_NO_PAINT_DEBUG
1315     if (flushed)
1316         QWidgetBackingStore::unflushPaint(q, toBePainted);
1317 #endif
1318
1319     if (q->paintingActive())
1320         qWarning("QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent");
1321 }
1322
1323
1324 QT_END_NAMESPACE