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