src/gui/painting/qbackingstore.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    43 #include "qplatformdefs.h"
       
    44 
       
    45 #include "qbackingstore_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 <QtGui/qapplication.h>
       
    52 #include <QtGui/qpaintengine.h>
       
    53 #include <QtGui/qgraphicsproxywidget.h>
       
    54 
       
    55 #include <private/qwidget_p.h>
       
    56 #include <private/qwindowsurface_raster_p.h>
       
    57 #include <private/qapplication_p.h>
       
    58 #include <private/qpaintengine_raster_p.h>
       
    59 #include <private/qgraphicseffect_p.h>
       
    60 
       
    61 #include "qgraphicssystem_p.h"
       
    62 
       
    63 #ifdef Q_WS_QWS
       
    64 #include <QtGui/qwsmanager_qws.h>
       
    65 #include <private/qwsmanager_p.h>
       
    66 #endif
       
    67 
       
    68 QT_BEGIN_NAMESPACE
       
    69 
       
    70 extern QRegion qt_dirtyRegion(QWidget *);
       
    71 
       
    72 /*
       
    73    A version of QRect::intersects() that does not normalize the rects.
       
    74 */
       
    75 static inline bool qRectIntersects(const QRect &r1, const QRect &r2)
       
    76 {
       
    77     return (qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right())
       
    78             && qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom()));
       
    79 }
       
    80 
       
    81 /**
       
    82  * Flushes the contents of the \a windowSurface into the screen area of \a widget.
       
    83  * \a tlwOffset is the position of the top level widget relative to the window surface.
       
    84  * \a region is the region to be updated in \a widget coordinates.
       
    85  */
       
    86 static inline void qt_flush(QWidget *widget, const QRegion &region, QWindowSurface *windowSurface,
       
    87                             QWidget *tlw, const QPoint &tlwOffset)
       
    88 {
       
    89     Q_ASSERT(widget);
       
    90     Q_ASSERT(!region.isEmpty());
       
    91     Q_ASSERT(windowSurface);
       
    92     Q_ASSERT(tlw);
       
    93 
       
    94 #if !defined(QT_NO_PAINT_DEBUG) && !defined(Q_WS_QWS)
       
    95     // QWS does flush update in QWindowSurface::flush (because it needs to lock the surface etc).
       
    96     static int flushUpdate = qgetenv("QT_FLUSH_UPDATE").toInt();
       
    97     if (flushUpdate > 0)
       
    98         QWidgetBackingStore::showYellowThing(widget, region, flushUpdate * 10, false);
       
    99 #endif
       
   100 
       
   101     if (widget != tlw)
       
   102         windowSurface->flush(widget, region, tlwOffset + widget->mapTo(tlw, QPoint()));
       
   103     else
       
   104         windowSurface->flush(widget, region, tlwOffset);
       
   105 }
       
   106 
       
   107 #ifndef QT_NO_PAINT_DEBUG
       
   108 #ifdef Q_WS_WIN
       
   109 static void showYellowThing_win(QWidget *widget, const QRegion &region, int msec)
       
   110 {
       
   111     HBRUSH brush;
       
   112     static int i = 0;
       
   113     switch (i) {
       
   114     case 0:
       
   115         brush = CreateSolidBrush(RGB(255, 255, 0));
       
   116         break;
       
   117     case 1:
       
   118         brush = CreateSolidBrush(RGB(255, 200, 55));
       
   119         break;
       
   120     case 2:
       
   121         brush = CreateSolidBrush(RGB(200, 255, 55));
       
   122         break;
       
   123     case 3:
       
   124         brush = CreateSolidBrush(RGB(200, 200, 0));
       
   125         break;
       
   126     }
       
   127     i = (i + 1) & 3;
       
   128 
       
   129     HDC hdc = widget->getDC();
       
   130 
       
   131     const QVector<QRect> &rects = region.rects();
       
   132     foreach (QRect rect, rects) {
       
   133         RECT winRect;
       
   134         SetRect(&winRect, rect.left(), rect.top(), rect.right(), rect.bottom());
       
   135         FillRect(hdc, &winRect, brush);
       
   136     }
       
   137 
       
   138     widget->releaseDC(hdc);
       
   139     ::Sleep(msec);
       
   140 }
       
   141 #endif
       
   142 
       
   143 void QWidgetBackingStore::showYellowThing(QWidget *widget, const QRegion &toBePainted, int msec, bool unclipped)
       
   144 {
       
   145 #ifdef Q_WS_QWS
       
   146     Q_UNUSED(widget);
       
   147     Q_UNUSED(unclipped);
       
   148     static QWSYellowSurface surface(true);
       
   149     surface.setDelay(msec);
       
   150     surface.flush(widget, toBePainted, QPoint());
       
   151 #else
       
   152     QRegion paintRegion = toBePainted;
       
   153     QRect widgetRect = widget->rect();
       
   154 
       
   155     if (!widget->internalWinId()) {
       
   156         QWidget *nativeParent = widget->nativeParentWidget();
       
   157         const QPoint offset = widget->mapTo(nativeParent, QPoint(0, 0));
       
   158         paintRegion.translate(offset);
       
   159         widgetRect.translate(offset);
       
   160         widget = nativeParent;
       
   161     }
       
   162 
       
   163 #ifdef Q_WS_WIN
       
   164     Q_UNUSED(unclipped);
       
   165     showYellowThing_win(widget, paintRegion, msec);
       
   166 #else
       
   167     //flags to fool painter
       
   168     bool paintUnclipped = widget->testAttribute(Qt::WA_PaintUnclipped);
       
   169     if (unclipped && !widget->d_func()->paintOnScreen())
       
   170         widget->setAttribute(Qt::WA_PaintUnclipped);
       
   171 
       
   172     const bool setFlag = !widget->testAttribute(Qt::WA_WState_InPaintEvent);
       
   173     if (setFlag)
       
   174         widget->setAttribute(Qt::WA_WState_InPaintEvent);
       
   175 
       
   176     //setup the engine
       
   177     QPaintEngine *pe = widget->paintEngine();
       
   178     if (pe) {
       
   179         pe->setSystemClip(paintRegion);
       
   180         {
       
   181             QPainter p(widget);
       
   182             p.setClipRegion(paintRegion);
       
   183             static int i = 0;
       
   184             switch (i) {
       
   185             case 0:
       
   186                 p.fillRect(widgetRect, QColor(255,255,0));
       
   187                 break;
       
   188             case 1:
       
   189                 p.fillRect(widgetRect, QColor(255,200,55));
       
   190                 break;
       
   191             case 2:
       
   192                 p.fillRect(widgetRect, QColor(200,255,55));
       
   193                 break;
       
   194             case 3:
       
   195                 p.fillRect(widgetRect, QColor(200,200,0));
       
   196                 break;
       
   197             }
       
   198             i = (i+1) & 3;
       
   199             p.end();
       
   200         }
       
   201     }
       
   202 
       
   203     if (setFlag)
       
   204         widget->setAttribute(Qt::WA_WState_InPaintEvent, false);
       
   205 
       
   206     //restore
       
   207     widget->setAttribute(Qt::WA_PaintUnclipped, paintUnclipped);
       
   208 
       
   209     if (pe)
       
   210         pe->setSystemClip(QRegion());
       
   211 
       
   212     QApplication::syncX();
       
   213 
       
   214 #if defined(Q_OS_UNIX)
       
   215     ::usleep(1000 * msec);
       
   216 #endif
       
   217 #endif // Q_WS_WIN
       
   218 #endif // Q_WS_QWS
       
   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->backingStore->windowSurface, 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 (dirty.intersects(tlwRect))
       
   267         return false; // We don't want to scroll junk.
       
   268     return windowSurface->scroll(tlwRect, dx, dy);
       
   269 }
       
   270 
       
   271 void QWidgetBackingStore::releaseBuffer()
       
   272 {
       
   273     if (windowSurface)
       
   274         windowSurface->setGeometry(QRect());
       
   275 #ifdef Q_BACKINGSTORE_SUBSURFACES
       
   276     for (int i = 0; i < subSurfaces.size(); ++i)
       
   277         subSurfaces.at(i)->setGeometry(QRect());
       
   278 #endif
       
   279 }
       
   280 
       
   281 /*!
       
   282     Prepares the window surface to paint a\ toClean region of the \a widget and
       
   283     updates the BeginPaintInfo struct accordingly.
       
   284 
       
   285     The \a toClean region might be clipped by the window surface.
       
   286 */
       
   287 void QWidgetBackingStore::beginPaint(QRegion &toClean, QWidget *widget, QWindowSurface *windowSurface,
       
   288                                      BeginPaintInfo *returnInfo, bool toCleanIsInTopLevelCoordinates)
       
   289 {
       
   290 #ifdef Q_WS_QWS
       
   291     QWSWindowSurface *surface = static_cast<QWSWindowSurface *>(windowSurface);
       
   292     QWidget *surfaceWidget = surface->window();
       
   293 
       
   294     if (!surface->isValid()) {
       
   295         // this looks strange but it really just releases the surface
       
   296         surface->releaseSurface();
       
   297         // the old window surface is deleted in setWindowSurface, which is
       
   298         // called from QWindowSurface constructor.
       
   299         windowSurface = tlw->d_func()->createDefaultWindowSurface();
       
   300         surface = static_cast<QWSWindowSurface *>(windowSurface);
       
   301         // createDefaultWindowSurface() will set topdata->windowSurface on the
       
   302         // widget to zero. However, if this is a sub-surface, it should point
       
   303         // to the widget's sub windowSurface, so we set that here:
       
   304         if (!surfaceWidget->isWindow())
       
   305             surfaceWidget->d_func()->topData()->windowSurface = windowSurface;
       
   306         surface->setGeometry(topLevelRect());
       
   307         returnInfo->windowSurfaceRecreated = true;
       
   308     }
       
   309 
       
   310     const QRegion toCleanUnclipped(toClean);
       
   311 
       
   312     if (surfaceWidget->isWindow())
       
   313         tlwOffset = surface->painterOffset();
       
   314 #ifdef Q_BACKINGSTORE_SUBSURFACES
       
   315     else if (toCleanIsInTopLevelCoordinates)
       
   316         toClean &= surface->clipRegion().translated(surfaceWidget->mapTo(tlw, QPoint()));
       
   317     if (!toCleanIsInTopLevelCoordinates && windowSurface == this->windowSurface)
       
   318         toClean &= surface->clipRegion().translated(-widget->mapTo(surfaceWidget, QPoint()));
       
   319 #else
       
   320     toClean &= surface->clipRegion();
       
   321 #endif
       
   322 
       
   323     if (toClean.isEmpty()) {
       
   324         if (surfaceWidget->isWindow()) {
       
   325             dirtyFromPreviousSync += toCleanUnclipped;
       
   326             hasDirtyFromPreviousSync = true;
       
   327         }
       
   328 
       
   329         returnInfo->nothingToPaint = true;
       
   330         // Nothing to repaint. However, we might have newly exposed areas on the
       
   331         // screen, so we have to make sure those are flushed.
       
   332         flush();
       
   333         return;
       
   334     }
       
   335 
       
   336     if (surfaceWidget->isWindow()) {
       
   337         if (toCleanUnclipped != toClean) {
       
   338             dirtyFromPreviousSync += (toCleanUnclipped - surface->clipRegion());
       
   339             hasDirtyFromPreviousSync = true;
       
   340         }
       
   341         if (hasDirtyFromPreviousSync) {
       
   342             dirtyFromPreviousSync -= toClean;
       
   343             hasDirtyFromPreviousSync = !dirtyFromPreviousSync.isEmpty();
       
   344         }
       
   345     }
       
   346 
       
   347 #endif // Q_WS_QWS
       
   348 
       
   349     Q_UNUSED(widget);
       
   350     Q_UNUSED(toCleanIsInTopLevelCoordinates);
       
   351 
       
   352     // Always flush repainted areas.
       
   353     dirtyOnScreen += toClean;
       
   354 
       
   355 #ifdef QT_NO_PAINT_DEBUG
       
   356     windowSurface->beginPaint(toClean);
       
   357 #else
       
   358     returnInfo->wasFlushed = QWidgetBackingStore::flushPaint(tlw, toClean);
       
   359     // Avoid deadlock with QT_FLUSH_PAINT: the server will wait for
       
   360     // the BackingStore lock, so if we hold that, the server will
       
   361     // never release the Communication lock that we are waiting for in
       
   362     // sendSynchronousCommand
       
   363     if (!returnInfo->wasFlushed)
       
   364         windowSurface->beginPaint(toClean);
       
   365 #endif
       
   366 
       
   367     Q_UNUSED(returnInfo);
       
   368 }
       
   369 
       
   370 void QWidgetBackingStore::endPaint(const QRegion &cleaned, QWindowSurface *windowSurface,
       
   371         BeginPaintInfo *beginPaintInfo)
       
   372 {
       
   373 #ifndef QT_NO_PAINT_DEBUG
       
   374     if (!beginPaintInfo->wasFlushed)
       
   375         windowSurface->endPaint(cleaned);
       
   376     else
       
   377         QWidgetBackingStore::unflushPaint(tlw, cleaned);
       
   378 #else
       
   379     Q_UNUSED(beginPaintInfo);
       
   380     windowSurface->endPaint(cleaned);
       
   381 #endif
       
   382 
       
   383 #ifdef Q_BACKINGSTORE_SUBSURFACES
       
   384     flush(static_cast<QWSWindowSurface *>(windowSurface)->window(), windowSurface);
       
   385 #else
       
   386     flush();
       
   387 #endif
       
   388 }
       
   389 
       
   390 /*!
       
   391     Returns the region (in top-level coordinates) that needs repaint and/or flush.
       
   392 
       
   393     If the widget is non-zero, only the dirty region for the widget is returned
       
   394     and the region will be in widget coordinates.
       
   395 */
       
   396 QRegion QWidgetBackingStore::dirtyRegion(QWidget *widget) const
       
   397 {
       
   398     const bool widgetDirty = widget && widget != tlw;
       
   399     const QRect tlwRect(topLevelRect());
       
   400     const QRect surfaceGeometry(windowSurface->geometry());
       
   401     if (surfaceGeometry != tlwRect && surfaceGeometry.size() != tlwRect.size()) {
       
   402         if (widgetDirty) {
       
   403             const QRect dirtyTlwRect = QRect(QPoint(), tlwRect.size());
       
   404             const QPoint offset(widget->mapTo(tlw, QPoint()));
       
   405             const QRect dirtyWidgetRect(dirtyTlwRect & widget->rect().translated(offset));
       
   406             return dirtyWidgetRect.translated(-offset);
       
   407         }
       
   408         return QRect(QPoint(), tlwRect.size());
       
   409     }
       
   410 
       
   411     // Calculate the region that needs repaint.
       
   412     QRegion r(dirty);
       
   413     for (int i = 0; i < dirtyWidgets.size(); ++i) {
       
   414         QWidget *w = dirtyWidgets.at(i);
       
   415         if (widgetDirty && w != widget && !widget->isAncestorOf(w))
       
   416             continue;
       
   417         r += w->d_func()->dirty.translated(w->mapTo(tlw, QPoint()));
       
   418     }
       
   419 
       
   420     // Append the region that needs flush.
       
   421     r += dirtyOnScreen;
       
   422 
       
   423     if (dirtyOnScreenWidgets) { // Only in use with native child widgets.
       
   424         for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) {
       
   425             QWidget *w = dirtyOnScreenWidgets->at(i);
       
   426             if (widgetDirty && w != widget && !widget->isAncestorOf(w))
       
   427                 continue;
       
   428             QWidgetPrivate *wd = w->d_func();
       
   429             Q_ASSERT(wd->needsFlush);
       
   430             r += wd->needsFlush->translated(w->mapTo(tlw, QPoint()));
       
   431         }
       
   432     }
       
   433 
       
   434     if (widgetDirty) {
       
   435         // Intersect with the widget geometry and translate to its coordinates.
       
   436         const QPoint offset(widget->mapTo(tlw, QPoint()));
       
   437         r &= widget->rect().translated(offset);
       
   438         r.translate(-offset);
       
   439     }
       
   440     return r;
       
   441 }
       
   442 
       
   443 /*!
       
   444     Returns the static content inside the \a parent if non-zero; otherwise the static content
       
   445     for the entire backing store is returned. The content will be clipped to \a withingClipRect
       
   446     if non-empty.
       
   447 */
       
   448 QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &withinClipRect) const
       
   449 {
       
   450     if (!parent && tlw->testAttribute(Qt::WA_StaticContents)) {
       
   451         const QRect surfaceGeometry(windowSurface->geometry());
       
   452         QRect surfaceRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height());
       
   453         if (!withinClipRect.isEmpty())
       
   454             surfaceRect &= withinClipRect;
       
   455         return QRegion(surfaceRect);
       
   456     }
       
   457 
       
   458     QRegion region;
       
   459     if (parent && parent->d_func()->children.isEmpty())
       
   460         return region;
       
   461 
       
   462     const bool clipToRect = !withinClipRect.isEmpty();
       
   463     const int count = staticWidgets.count();
       
   464     for (int i = 0; i < count; ++i) {
       
   465         QWidget *w = staticWidgets.at(i);
       
   466         QWidgetPrivate *wd = w->d_func();
       
   467         if (!wd->isOpaque || !wd->extra || wd->extra->staticContentsSize.isEmpty()
       
   468             || !w->isVisible() || (parent && !parent->isAncestorOf(w))) {
       
   469             continue;
       
   470         }
       
   471 
       
   472         QRect rect(0, 0, wd->extra->staticContentsSize.width(), wd->extra->staticContentsSize.height());
       
   473         const QPoint offset = w->mapTo(parent ? parent : tlw, QPoint());
       
   474         if (clipToRect)
       
   475             rect &= withinClipRect.translated(-offset);
       
   476         if (rect.isEmpty())
       
   477             continue;
       
   478 
       
   479         rect &= wd->clipRect();
       
   480         if (rect.isEmpty())
       
   481             continue;
       
   482 
       
   483         QRegion visible(rect);
       
   484         wd->clipToEffectiveMask(visible);
       
   485         if (visible.isEmpty())
       
   486             continue;
       
   487         wd->subtractOpaqueSiblings(visible, 0, /*alsoNonOpaque=*/true);
       
   488 
       
   489         visible.translate(offset);
       
   490         region += visible;
       
   491     }
       
   492 
       
   493     return region;
       
   494 }
       
   495 
       
   496 static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately)
       
   497 {
       
   498     if (!widget)
       
   499         return;
       
   500 
       
   501 #if defined(Q_WS_WIN) && !defined(Q_OS_WINCE)
       
   502     if (QApplicationPrivate::inSizeMove && widget->internalWinId() && !updateImmediately
       
   503         && !widget->testAttribute(Qt::WA_DontShowOnScreen)) {
       
   504         // Tell Windows to send us a paint event if we're in WM_SIZE/WM_MOVE; posted events
       
   505         // are blocked until the mouse button is released. See task 146849.
       
   506         const QRegion rgn(qt_dirtyRegion(widget));
       
   507         InvalidateRgn(widget->internalWinId(), rgn.handle(), false);
       
   508         qt_widget_private(widget)->dirty = QRegion();
       
   509         return;
       
   510     }
       
   511 #endif
       
   512 
       
   513     if (updateImmediately) {
       
   514         QEvent event(QEvent::UpdateRequest);
       
   515         QApplication::sendEvent(widget, &event);
       
   516     } else {
       
   517         QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
       
   518     }
       
   519 }
       
   520 
       
   521 /*!
       
   522     Marks the region of the widget as dirty (if not already marked as dirty) and
       
   523     posts an UpdateRequest event to the top-level widget (if not already posted).
       
   524 
       
   525     If updateImmediately is true, the event is sent immediately instead of posted.
       
   526 
       
   527     If invalidateBuffer is true, all widgets intersecting with the region will be dirty.
       
   528 
       
   529     If the widget paints directly on screen, the event is sent to the widget
       
   530     instead of the top-level widget, and invalidateBuffer is completely ignored.
       
   531 
       
   532     ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
       
   533 */
       
   534 void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool updateImmediately,
       
   535                                     bool invalidateBuffer)
       
   536 {
       
   537     Q_ASSERT(tlw->d_func()->extra);
       
   538     Q_ASSERT(tlw->d_func()->extra->topextra);
       
   539     Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize);
       
   540     Q_ASSERT(widget->isVisible() && widget->updatesEnabled());
       
   541     Q_ASSERT(widget->window() == tlw);
       
   542     Q_ASSERT(!rgn.isEmpty());
       
   543 
       
   544     widget->d_func()->invalidateGraphicsEffectsRecursively();
       
   545 
       
   546     if (widget->d_func()->paintOnScreen()) {
       
   547         if (widget->d_func()->dirty.isEmpty()) {
       
   548             widget->d_func()->dirty = rgn;
       
   549             sendUpdateRequest(widget, updateImmediately);
       
   550             return;
       
   551         } else if (qt_region_strictContains(widget->d_func()->dirty, widget->rect())) {
       
   552             if (updateImmediately)
       
   553                 sendUpdateRequest(widget, updateImmediately);
       
   554             return; // Already dirty.
       
   555         }
       
   556 
       
   557         const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty();
       
   558         widget->d_func()->dirty += rgn;
       
   559         if (!eventAlreadyPosted || updateImmediately)
       
   560             sendUpdateRequest(widget, updateImmediately);
       
   561         return;
       
   562     }
       
   563 
       
   564     const QPoint offset = widget->mapTo(tlw, QPoint());
       
   565     const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect());
       
   566     if (qt_region_strictContains(dirty, widgetRect.translated(offset))) {
       
   567         if (updateImmediately)
       
   568             sendUpdateRequest(tlw, updateImmediately);
       
   569         return; // Already dirty.
       
   570     }
       
   571 
       
   572     if (invalidateBuffer) {
       
   573         const bool eventAlreadyPosted = !dirty.isEmpty();
       
   574         if (widget->d_func()->graphicsEffect)
       
   575             dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset);
       
   576         else
       
   577             dirty += rgn.translated(offset);
       
   578         if (!eventAlreadyPosted || updateImmediately)
       
   579             sendUpdateRequest(tlw, updateImmediately);
       
   580         return;
       
   581     }
       
   582 
       
   583     if (dirtyWidgets.isEmpty()) {
       
   584         addDirtyWidget(widget, rgn);
       
   585         sendUpdateRequest(tlw, updateImmediately);
       
   586         return;
       
   587     }
       
   588 
       
   589     if (widget->d_func()->inDirtyList) {
       
   590         if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) {
       
   591             if (widget->d_func()->graphicsEffect)
       
   592                 widget->d_func()->dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect());
       
   593             else
       
   594                 widget->d_func()->dirty += rgn;
       
   595         }
       
   596     } else {
       
   597         addDirtyWidget(widget, rgn);
       
   598     }
       
   599 
       
   600     if (updateImmediately)
       
   601         sendUpdateRequest(tlw, updateImmediately);
       
   602 }
       
   603 
       
   604 /*!
       
   605     This function is equivalent to calling markDirty(QRegion(rect), ...), but
       
   606     is more efficient as it eliminates QRegion operations/allocations and can
       
   607     use the rect more precisely for additional cut-offs.
       
   608 
       
   609     ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
       
   610 */
       
   611 void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool updateImmediately,
       
   612                                     bool invalidateBuffer)
       
   613 {
       
   614     Q_ASSERT(tlw->d_func()->extra);
       
   615     Q_ASSERT(tlw->d_func()->extra->topextra);
       
   616     Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize);
       
   617     Q_ASSERT(widget->isVisible() && widget->updatesEnabled());
       
   618     Q_ASSERT(widget->window() == tlw);
       
   619     Q_ASSERT(!rect.isEmpty());
       
   620 
       
   621     widget->d_func()->invalidateGraphicsEffectsRecursively();
       
   622 
       
   623     if (widget->d_func()->paintOnScreen()) {
       
   624         if (widget->d_func()->dirty.isEmpty()) {
       
   625             widget->d_func()->dirty = QRegion(rect);
       
   626             sendUpdateRequest(widget, updateImmediately);
       
   627             return;
       
   628         } else if (qt_region_strictContains(widget->d_func()->dirty, rect)) {
       
   629             if (updateImmediately)
       
   630                 sendUpdateRequest(widget, updateImmediately);
       
   631             return; // Already dirty.
       
   632         }
       
   633 
       
   634         const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty();
       
   635         widget->d_func()->dirty += rect;
       
   636         if (!eventAlreadyPosted || updateImmediately)
       
   637             sendUpdateRequest(widget, updateImmediately);
       
   638         return;
       
   639     }
       
   640 
       
   641     const QRect widgetRect = widget->d_func()->effectiveRectFor(rect);
       
   642     const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint())));
       
   643     if (qt_region_strictContains(dirty, translatedRect)) {
       
   644         if (updateImmediately)
       
   645             sendUpdateRequest(tlw, updateImmediately);
       
   646         return; // Already dirty
       
   647     }
       
   648 
       
   649     if (invalidateBuffer) {
       
   650         const bool eventAlreadyPosted = !dirty.isEmpty();
       
   651         dirty += translatedRect;
       
   652         if (!eventAlreadyPosted || updateImmediately)
       
   653             sendUpdateRequest(tlw, updateImmediately);
       
   654         return;
       
   655     }
       
   656 
       
   657     if (dirtyWidgets.isEmpty()) {
       
   658         addDirtyWidget(widget, rect);
       
   659         sendUpdateRequest(tlw, updateImmediately);
       
   660         return;
       
   661     }
       
   662 
       
   663     if (widget->d_func()->inDirtyList) {
       
   664         if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect))
       
   665             widget->d_func()->dirty += widgetRect;
       
   666     } else {
       
   667         addDirtyWidget(widget, rect);
       
   668     }
       
   669 
       
   670     if (updateImmediately)
       
   671         sendUpdateRequest(tlw, updateImmediately);
       
   672 }
       
   673 
       
   674 /*!
       
   675     Marks the \a region of the \a widget as dirty on screen. The \a region will be copied from
       
   676     the backing store to the \a widget's native parent next time flush() is called.
       
   677 
       
   678     Paint on screen widgets are ignored.
       
   679 */
       
   680 void QWidgetBackingStore::markDirtyOnScreen(const QRegion &region, QWidget *widget, const QPoint &topLevelOffset)
       
   681 {
       
   682     if (!widget || widget->d_func()->paintOnScreen() || region.isEmpty())
       
   683         return;
       
   684 
       
   685 #if defined(Q_WS_QWS) || defined(Q_WS_MAC)
       
   686     if (!widget->testAttribute(Qt::WA_WState_InPaintEvent))
       
   687         dirtyOnScreen += region.translated(topLevelOffset);
       
   688     return;
       
   689 #endif
       
   690 
       
   691     // Top-level.
       
   692     if (widget == tlw) {
       
   693         if (!widget->testAttribute(Qt::WA_WState_InPaintEvent))
       
   694             dirtyOnScreen += region;
       
   695         return;
       
   696     }
       
   697 
       
   698     // Alien widgets.
       
   699     if (!widget->internalWinId()) {
       
   700         QWidget *nativeParent = widget->nativeParentWidget();
       
   701         // Alien widgets with the top-level as the native parent (common case).
       
   702         if (nativeParent == tlw) {
       
   703             if (!widget->testAttribute(Qt::WA_WState_InPaintEvent))
       
   704                 dirtyOnScreen += region.translated(topLevelOffset);
       
   705             return;
       
   706         }
       
   707 
       
   708         // Alien widgets with native parent != tlw.
       
   709         QWidgetPrivate *nativeParentPrivate = nativeParent->d_func();
       
   710         if (!nativeParentPrivate->needsFlush)
       
   711             nativeParentPrivate->needsFlush = new QRegion;
       
   712         const QPoint nativeParentOffset = widget->mapTo(nativeParent, QPoint());
       
   713         *nativeParentPrivate->needsFlush += region.translated(nativeParentOffset);
       
   714         appendDirtyOnScreenWidget(nativeParent);
       
   715         return;
       
   716     }
       
   717 
       
   718     // Native child widgets.
       
   719     QWidgetPrivate *widgetPrivate = widget->d_func();
       
   720     if (!widgetPrivate->needsFlush)
       
   721         widgetPrivate->needsFlush = new QRegion;
       
   722     *widgetPrivate->needsFlush += region;
       
   723     appendDirtyOnScreenWidget(widget);
       
   724 }
       
   725 
       
   726 void QWidgetBackingStore::removeDirtyWidget(QWidget *w)
       
   727 {
       
   728     if (!w)
       
   729         return;
       
   730 
       
   731     dirtyWidgetsRemoveAll(w);
       
   732     dirtyOnScreenWidgetsRemoveAll(w);
       
   733     resetWidget(w);
       
   734 
       
   735     QWidgetPrivate *wd = w->d_func();
       
   736     const int n = wd->children.count();
       
   737     for (int i = 0; i < n; ++i) {
       
   738         if (QWidget *child = qobject_cast<QWidget*>(wd->children.at(i)))
       
   739             removeDirtyWidget(child);
       
   740     }
       
   741 }
       
   742 
       
   743 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER)
       
   744 bool QWidgetBackingStore::hasDirtyWindowDecoration() const
       
   745 {
       
   746     QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
       
   747     if (tlwExtra && tlwExtra->qwsManager)
       
   748         return !tlwExtra->qwsManager->d_func()->dirtyRegions.isEmpty();
       
   749     return false;
       
   750 }
       
   751 
       
   752 void QWidgetBackingStore::paintWindowDecoration()
       
   753 {
       
   754     if (!hasDirtyWindowDecoration())
       
   755         return;
       
   756 
       
   757     QDecoration &decoration = QApplication::qwsDecoration();
       
   758     const QRect decorationRect = tlw->rect();
       
   759     QRegion decorationRegion = decoration.region(tlw, decorationRect);
       
   760 
       
   761     QWSManagerPrivate *managerPrivate = tlw->d_func()->topData()->qwsManager->d_func();
       
   762     const bool doClipping = !managerPrivate->entireDecorationNeedsRepaint
       
   763                             && !managerPrivate->dirtyClip.isEmpty();
       
   764 
       
   765     if (doClipping) {
       
   766         decorationRegion &= static_cast<QWSWindowSurface *>(windowSurface)->clipRegion();
       
   767         decorationRegion &= managerPrivate->dirtyClip;
       
   768     }
       
   769 
       
   770     if (decorationRegion.isEmpty())
       
   771         return;
       
   772 
       
   773     windowSurface->beginPaint(decorationRegion);
       
   774 
       
   775     QPaintEngine *engine = windowSurface->paintDevice()->paintEngine();
       
   776     Q_ASSERT(engine);
       
   777     const QRegion oldSystemClip(engine->systemClip());
       
   778     engine->setSystemClip(decorationRegion.translated(tlwOffset));
       
   779 
       
   780     QPainter painter(windowSurface->paintDevice());
       
   781     painter.setFont(QApplication::font());
       
   782     painter.translate(tlwOffset);
       
   783 
       
   784     const int numDirty = managerPrivate->dirtyRegions.size();
       
   785     for (int i = 0; i < numDirty; ++i) {
       
   786         const int area = managerPrivate->dirtyRegions.at(i);
       
   787 
       
   788         QRegion clipRegion = decoration.region(tlw, decorationRect, area);
       
   789         if (!clipRegion.isEmpty()) {
       
   790             // Decoration styles changes the clip and assumes the old clip is non-empty,
       
   791             // so we have to set it, but in theory it shouldn't be required.
       
   792             painter.setClipRegion(clipRegion);
       
   793             decoration.paint(&painter, tlw, area, managerPrivate->dirtyStates.at(i));
       
   794         }
       
   795     }
       
   796     markDirtyOnScreen(decorationRegion, tlw, QPoint());
       
   797 
       
   798     painter.end();
       
   799     windowSurface->endPaint(decorationRegion);
       
   800     managerPrivate->clearDirtyRegions();
       
   801     engine->setSystemClip(oldSystemClip);
       
   802 }
       
   803 #endif
       
   804 
       
   805 void QWidgetBackingStore::updateLists(QWidget *cur)
       
   806 {
       
   807     if (!cur)
       
   808         return;
       
   809 
       
   810     QList<QObject*> children = cur->children();
       
   811     for (int i = 0; i < children.size(); ++i) {
       
   812         QWidget *child = qobject_cast<QWidget*>(children.at(i));
       
   813         if (!child)
       
   814             continue;
       
   815 
       
   816         updateLists(child);
       
   817     }
       
   818 
       
   819     if (cur->testAttribute(Qt::WA_StaticContents))
       
   820         addStaticWidget(cur);
       
   821 
       
   822 #ifdef Q_BACKINGSTORE_SUBSURFACES
       
   823     QTLWExtra *extra = cur->d_func()->maybeTopData();
       
   824     if (extra && extra->windowSurface && cur != tlw)
       
   825         subSurfaces.append(extra->windowSurface);
       
   826 #endif
       
   827 }
       
   828 
       
   829 QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel)
       
   830     : tlw(topLevel), dirtyOnScreenWidgets(0), hasDirtyFromPreviousSync(false)
       
   831 {
       
   832     windowSurface = tlw->windowSurface();
       
   833     if (!windowSurface)
       
   834         windowSurface = topLevel->d_func()->createDefaultWindowSurface();
       
   835 
       
   836     // The QWindowSurface constructor will call QWidget::setWindowSurface(),
       
   837     // but automatically created surfaces should not be added to the topdata.
       
   838 #ifdef Q_BACKINGSTORE_SUBSURFACES
       
   839     Q_ASSERT(topLevel->d_func()->topData()->windowSurface == windowSurface);
       
   840 #endif
       
   841     topLevel->d_func()->topData()->windowSurface = 0;
       
   842 
       
   843     // Ensure all existing subsurfaces and static widgets are added to their respective lists.
       
   844     updateLists(topLevel);
       
   845 }
       
   846 
       
   847 QWidgetBackingStore::~QWidgetBackingStore()
       
   848 {
       
   849     for (int c = 0; c < dirtyWidgets.size(); ++c) {
       
   850         resetWidget(dirtyWidgets.at(c));
       
   851     }
       
   852 
       
   853     delete windowSurface;
       
   854     windowSurface = 0;
       
   855     delete dirtyOnScreenWidgets;
       
   856     dirtyOnScreenWidgets = 0;
       
   857 }
       
   858 
       
   859 //parent's coordinates; move whole rect; update parent and widget
       
   860 //assume the screen blt has already been done, so we don't need to refresh that part
       
   861 void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy)
       
   862 {
       
   863     Q_Q(QWidget);
       
   864     if (!q->isVisible() || (dx == 0 && dy == 0))
       
   865         return;
       
   866 
       
   867     QWidget *tlw = q->window();
       
   868     QTLWExtra* x = tlw->d_func()->topData();
       
   869     if (x->inTopLevelResize)
       
   870         return;
       
   871 
       
   872     static int accelEnv = -1;
       
   873     if (accelEnv == -1) {
       
   874         accelEnv = qgetenv("QT_NO_FAST_MOVE").toInt() == 0;
       
   875     }
       
   876 
       
   877     QWidget *pw = q->parentWidget();
       
   878     QPoint toplevelOffset = pw->mapTo(tlw, QPoint());
       
   879     QWidgetPrivate *pd = pw->d_func();
       
   880     QRect clipR(pd->clipRect());
       
   881 #ifdef Q_WS_QWS
       
   882     QWidgetBackingStore *wbs = x->backingStore;
       
   883     QWSWindowSurface *surface = static_cast<QWSWindowSurface*>(wbs->windowSurface);
       
   884     clipR = clipR.intersected(surface->clipRegion().translated(-toplevelOffset).boundingRect());
       
   885 #endif
       
   886     const QRect newRect(rect.translated(dx, dy));
       
   887     QRect destRect = rect.intersected(clipR);
       
   888     if (destRect.isValid())
       
   889         destRect = destRect.translated(dx, dy).intersected(clipR);
       
   890     const QRect sourceRect(destRect.translated(-dx, -dy));
       
   891     const QRect parentRect(rect & clipR);
       
   892 
       
   893     bool accelerateMove = accelEnv && isOpaque
       
   894 #ifndef QT_NO_GRAPHICSCVIEW
       
   895                           // No accelerate move for proxy widgets.
       
   896                           && !tlw->d_func()->extra->proxyWidget
       
   897 #endif
       
   898                           && !isOverlapped(sourceRect) && !isOverlapped(destRect);
       
   899 
       
   900     if (!accelerateMove) {
       
   901         QRegion parentR(effectiveRectFor(parentRect));
       
   902         if (!extra || !extra->hasMask) {
       
   903             parentR -= newRect;
       
   904         } else {
       
   905             // invalidateBuffer() excludes anything outside the mask
       
   906             parentR += newRect & clipR;
       
   907         }
       
   908         pd->invalidateBuffer(parentR);
       
   909         invalidateBuffer((newRect & clipR).translated(-data.crect.topLeft()));
       
   910     } else {
       
   911 
       
   912         QWidgetBackingStore *wbs = x->backingStore;
       
   913         QRegion childExpose(newRect & clipR);
       
   914 
       
   915         if (sourceRect.isValid() && wbs->bltRect(sourceRect, dx, dy, pw))
       
   916             childExpose -= destRect;
       
   917 
       
   918         if (!pw->updatesEnabled())
       
   919             return;
       
   920 
       
   921         const bool childUpdatesEnabled = q->updatesEnabled();
       
   922         if (childUpdatesEnabled && !childExpose.isEmpty()) {
       
   923             childExpose.translate(-data.crect.topLeft());
       
   924             wbs->markDirty(childExpose, q);
       
   925             isMoved = true;
       
   926         }
       
   927 
       
   928         QRegion parentExpose(parentRect);
       
   929         parentExpose -= newRect;
       
   930         if (extra && extra->hasMask)
       
   931             parentExpose += QRegion(newRect) - extra->mask.translated(data.crect.topLeft());
       
   932 
       
   933         if (!parentExpose.isEmpty()) {
       
   934             wbs->markDirty(parentExpose, pw);
       
   935             pd->isMoved = true;
       
   936         }
       
   937 
       
   938         if (childUpdatesEnabled) {
       
   939             QRegion needsFlush(sourceRect);
       
   940             needsFlush += destRect;
       
   941             wbs->markDirtyOnScreen(needsFlush, pw, toplevelOffset);
       
   942         }
       
   943     }
       
   944 }
       
   945 
       
   946 //widget's coordinates; scroll within rect;  only update widget
       
   947 void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy)
       
   948 {
       
   949     Q_Q(QWidget);
       
   950     QWidget *tlw = q->window();
       
   951     QTLWExtra* x = tlw->d_func()->topData();
       
   952     if (x->inTopLevelResize)
       
   953         return;
       
   954 
       
   955     QWidgetBackingStore *wbs = x->backingStore;
       
   956 
       
   957     static int accelEnv = -1;
       
   958     if (accelEnv == -1) {
       
   959         accelEnv = qgetenv("QT_NO_FAST_SCROLL").toInt() == 0;
       
   960     }
       
   961 
       
   962     QRect scrollRect = rect & clipRect();
       
   963     bool overlapped = false;
       
   964     bool accelerateScroll = accelEnv && isOpaque
       
   965                             && !(overlapped = isOverlapped(scrollRect.translated(data.crect.topLeft())));
       
   966 
       
   967 #if defined(Q_WS_QWS)
       
   968     QWSWindowSurface *surface;
       
   969     surface = static_cast<QWSWindowSurface*>(wbs->windowSurface);
       
   970 
       
   971     if (accelerateScroll && !surface->isBuffered()) {
       
   972         const QRegion surfaceClip = surface->clipRegion();
       
   973         const QRegion outsideClip = QRegion(rect) - surfaceClip;
       
   974         if (!outsideClip.isEmpty()) {
       
   975             const QVector<QRect> clipped = (surfaceClip & rect).rects();
       
   976             if (clipped.size() < 8) {
       
   977                 for (int i = 0; i < clipped.size(); ++i)
       
   978                     this->scrollRect(clipped.at(i), dx, dy);
       
   979                 return;
       
   980             } else {
       
   981                 accelerateScroll = false;
       
   982             }
       
   983         }
       
   984     }
       
   985 #endif // Q_WS_QWS
       
   986 
       
   987     if (!accelerateScroll) {
       
   988         if (overlapped) {
       
   989             QRegion region(scrollRect);
       
   990             subtractOpaqueSiblings(region);
       
   991             invalidateBuffer(region);
       
   992         }else {
       
   993             invalidateBuffer(scrollRect);
       
   994         }
       
   995     } else {
       
   996         const QPoint toplevelOffset = q->mapTo(tlw, QPoint());
       
   997 #ifdef Q_WS_QWS
       
   998         QWSWindowSurface *surface = static_cast<QWSWindowSurface*>(wbs->windowSurface);
       
   999         const QRegion clip = surface->clipRegion().translated(-toplevelOffset) & scrollRect;
       
  1000         const QRect clipBoundingRect = clip.boundingRect();
       
  1001         scrollRect &= clipBoundingRect;
       
  1002 #endif
       
  1003         const QRect destRect = scrollRect.translated(dx, dy) & scrollRect;
       
  1004         const QRect sourceRect = destRect.translated(-dx, -dy);
       
  1005 
       
  1006         QRegion childExpose(scrollRect);
       
  1007         if (sourceRect.isValid()) {
       
  1008             if (wbs->bltRect(sourceRect, dx, dy, q))
       
  1009                 childExpose -= destRect;
       
  1010         }
       
  1011 
       
  1012         if (inDirtyList) {
       
  1013             if (rect == q->rect()) {
       
  1014                 dirty.translate(dx, dy);
       
  1015             } else {
       
  1016                 QRegion dirtyScrollRegion = dirty.intersected(scrollRect);
       
  1017                 if (!dirtyScrollRegion.isEmpty()) {
       
  1018                     dirty -= dirtyScrollRegion;
       
  1019                     dirtyScrollRegion.translate(dx, dy);
       
  1020                     dirty += dirtyScrollRegion;
       
  1021                 }
       
  1022             }
       
  1023         }
       
  1024 
       
  1025         if (!q->updatesEnabled())
       
  1026             return;
       
  1027 
       
  1028         if (!childExpose.isEmpty()) {
       
  1029             wbs->markDirty(childExpose, q);
       
  1030             isScrolled = true;
       
  1031         }
       
  1032 
       
  1033         // Instead of using native scroll-on-screen, we copy from
       
  1034         // backingstore, giving only one screen update for each
       
  1035         // scroll, and a solid appearance
       
  1036         wbs->markDirtyOnScreen(destRect, q, toplevelOffset);
       
  1037     }
       
  1038 }
       
  1039 
       
  1040 static inline bool discardSyncRequest(QWidget *tlw, QTLWExtra *tlwExtra)
       
  1041 {
       
  1042     if (!tlw || !tlwExtra)
       
  1043         return true;
       
  1044 
       
  1045 #ifdef Q_WS_X11
       
  1046     // Delay the sync until we get an Expose event from X11 (initial show).
       
  1047     // Qt::WA_Mapped is set to true, but the actual mapping has not yet occurred.
       
  1048     // However, we must repaint immediately regardless of the state if someone calls repaint().
       
  1049     if (tlwExtra->waitingForMapNotify && !tlwExtra->inRepaint)
       
  1050         return true;
       
  1051 #endif
       
  1052 
       
  1053     if (!tlw->testAttribute(Qt::WA_Mapped))
       
  1054         return true;
       
  1055 
       
  1056     if (!tlw->isVisible()
       
  1057 #ifndef Q_WS_X11
       
  1058         // If we're minimized on X11, WA_Mapped will be false and we
       
  1059         // will return in the case above. Some window managers on X11
       
  1060         // sends us the PropertyNotify to change the minimized state
       
  1061         // *AFTER* we've received the expose event, which is baaad.
       
  1062         || tlw->isMinimized()
       
  1063 #endif
       
  1064         )
       
  1065         return true;
       
  1066 
       
  1067     return false;
       
  1068 }
       
  1069 
       
  1070 /*!
       
  1071     Synchronizes the \a exposedRegion of the \a exposedWidget with the backing store.
       
  1072 
       
  1073     If there's nothing to repaint, the area is flushed and painting does not occur;
       
  1074     otherwise the area is marked as dirty on screen and will be flushed right after
       
  1075     we are done with all painting.
       
  1076 */
       
  1077 void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedRegion)
       
  1078 {
       
  1079     QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
       
  1080     if (discardSyncRequest(tlw, tlwExtra) || tlwExtra->inTopLevelResize)
       
  1081         return;
       
  1082 
       
  1083     if (!exposedWidget || !exposedWidget->internalWinId() || !exposedWidget->isVisible()
       
  1084         || !exposedWidget->updatesEnabled() || exposedRegion.isEmpty()) {
       
  1085         return;
       
  1086     }
       
  1087 
       
  1088     // Nothing to repaint.
       
  1089     if (!isDirty()) {
       
  1090         qt_flush(exposedWidget, exposedRegion, windowSurface, tlw, tlwOffset);
       
  1091         return;
       
  1092     }
       
  1093 
       
  1094     if (exposedWidget != tlw)
       
  1095         markDirtyOnScreen(exposedRegion, exposedWidget, exposedWidget->mapTo(tlw, QPoint()));
       
  1096     else
       
  1097         markDirtyOnScreen(exposedRegion, exposedWidget, QPoint());
       
  1098     sync();
       
  1099 }
       
  1100 
       
  1101 /*!
       
  1102     Synchronizes the backing store, i.e. dirty areas are repainted and flushed.
       
  1103 */
       
  1104 void QWidgetBackingStore::sync()
       
  1105 {
       
  1106     QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
       
  1107     if (discardSyncRequest(tlw, tlwExtra)) {
       
  1108         // If the top-level is minimized, it's not visible on the screen so we can delay the
       
  1109         // update until it's shown again. In order to do that we must keep the dirty states.
       
  1110         // These will be cleared when we receive the first expose after showNormal().
       
  1111         // However, if the widget is not visible (isVisible() returns false), everything will
       
  1112         // be invalidated once the widget is shown again, so clear all dirty states.
       
  1113         if (!tlw->isVisible()) {
       
  1114             dirty = QRegion();
       
  1115             for (int i = 0; i < dirtyWidgets.size(); ++i)
       
  1116                 resetWidget(dirtyWidgets.at(i));
       
  1117             dirtyWidgets.clear();
       
  1118         }
       
  1119         return;
       
  1120     }
       
  1121 
       
  1122     const bool inTopLevelResize = tlwExtra->inTopLevelResize;
       
  1123     const bool updatesDisabled = !tlw->updatesEnabled();
       
  1124     const QRect tlwRect(topLevelRect());
       
  1125     const QRect surfaceGeometry(windowSurface->geometry());
       
  1126     bool repaintAllWidgets = false;
       
  1127 
       
  1128     if (inTopLevelResize || surfaceGeometry != tlwRect) {
       
  1129         if ((inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) {
       
  1130             if (hasStaticContents()) {
       
  1131                 // Repaint existing dirty area and newly visible area.
       
  1132                 const QRect clipRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height());
       
  1133                 const QRegion staticRegion(staticContents(0, clipRect));
       
  1134                 QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height());
       
  1135                 newVisible -= staticRegion;
       
  1136                 dirty += newVisible;
       
  1137                 windowSurface->setStaticContents(staticRegion);
       
  1138             } else {
       
  1139                 // Repaint everything.
       
  1140                 dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height());
       
  1141                 for (int i = 0; i < dirtyWidgets.size(); ++i)
       
  1142                     resetWidget(dirtyWidgets.at(i));
       
  1143                 dirtyWidgets.clear();
       
  1144                 repaintAllWidgets = true;
       
  1145             }
       
  1146         }
       
  1147         windowSurface->setGeometry(tlwRect);
       
  1148     }
       
  1149 
       
  1150     if (updatesDisabled)
       
  1151         return;
       
  1152 
       
  1153     if (hasDirtyFromPreviousSync)
       
  1154         dirty += dirtyFromPreviousSync;
       
  1155 
       
  1156     // Contains everything that needs repaint.
       
  1157     QRegion toClean(dirty);
       
  1158 
       
  1159     // Loop through all update() widgets and remove them from the list before they are
       
  1160     // painted (in case someone calls update() in paintEvent). If the widget is opaque
       
  1161     // and does not have transparent overlapping siblings, append it to the
       
  1162     // opaqueNonOverlappedWidgets list and paint it directly without composition.
       
  1163     QVarLengthArray<QWidget *, 32> opaqueNonOverlappedWidgets;
       
  1164     for (int i = 0; i < dirtyWidgets.size(); ++i) {
       
  1165         QWidget *w = dirtyWidgets.at(i);
       
  1166         QWidgetPrivate *wd = w->d_func();
       
  1167         if (wd->data.in_destructor)
       
  1168             continue;
       
  1169 
       
  1170         // Clip with mask() and clipRect().
       
  1171         wd->dirty &= wd->clipRect();
       
  1172         wd->clipToEffectiveMask(wd->dirty);
       
  1173 
       
  1174         // Subtract opaque siblings and children.
       
  1175         bool hasDirtySiblingsAbove = false;
       
  1176         // We know for sure that the widget isn't overlapped if 'isMoved' is true.
       
  1177         if (!wd->isMoved)
       
  1178             wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove);
       
  1179         // Scrolled and moved widgets must draw all children.
       
  1180         if (!wd->isScrolled && !wd->isMoved)
       
  1181             wd->subtractOpaqueChildren(wd->dirty, w->rect());
       
  1182 
       
  1183         if (wd->dirty.isEmpty()) {
       
  1184             resetWidget(w);
       
  1185             continue;
       
  1186         }
       
  1187 
       
  1188         const QRegion widgetDirty(w != tlw ? wd->dirty.translated(w->mapTo(tlw, QPoint()))
       
  1189                                            : wd->dirty);
       
  1190         toClean += widgetDirty;
       
  1191 
       
  1192 #ifndef QT_NO_GRAPHICSCVIEW
       
  1193         if (tlw->d_func()->extra->proxyWidget) {
       
  1194             resetWidget(w);
       
  1195             continue;
       
  1196         }
       
  1197 #endif
       
  1198 
       
  1199         if (!hasDirtySiblingsAbove && wd->isOpaque && !dirty.intersects(widgetDirty.boundingRect())) {
       
  1200             opaqueNonOverlappedWidgets.append(w);
       
  1201         } else {
       
  1202             resetWidget(w);
       
  1203             dirty += widgetDirty;
       
  1204         }
       
  1205     }
       
  1206     dirtyWidgets.clear();
       
  1207 
       
  1208     if (toClean.isEmpty()) {
       
  1209         // Nothing to repaint. However, we might have newly exposed areas on the
       
  1210         // screen if this function was called from sync(QWidget *, QRegion)), so
       
  1211         // we have to make sure those are flushed.
       
  1212         flush();
       
  1213         return;
       
  1214     }
       
  1215 
       
  1216 #ifndef QT_NO_GRAPHICSVIEW
       
  1217     if (tlw->d_func()->extra->proxyWidget) {
       
  1218         updateStaticContentsSize();
       
  1219         dirty = QRegion();
       
  1220         const QVector<QRect> rects(toClean.rects());
       
  1221         for (int i = 0; i < rects.size(); ++i)
       
  1222             tlw->d_func()->extra->proxyWidget->update(rects.at(i));
       
  1223         return;
       
  1224     }
       
  1225 #endif
       
  1226 
       
  1227 #ifndef Q_BACKINGSTORE_SUBSURFACES
       
  1228     BeginPaintInfo beginPaintInfo;
       
  1229     beginPaint(toClean, tlw, windowSurface, &beginPaintInfo);
       
  1230     if (beginPaintInfo.nothingToPaint) {
       
  1231         for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i)
       
  1232             resetWidget(opaqueNonOverlappedWidgets[i]);
       
  1233         dirty = QRegion();
       
  1234         return;
       
  1235     }
       
  1236 #endif
       
  1237 
       
  1238     // Must do this before sending any paint events because
       
  1239     // the size may change in the paint event.
       
  1240     updateStaticContentsSize();
       
  1241     const QRegion dirtyCopy(dirty);
       
  1242     dirty = QRegion();
       
  1243 
       
  1244     // Paint opaque non overlapped widgets.
       
  1245     for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) {
       
  1246         QWidget *w = opaqueNonOverlappedWidgets[i];
       
  1247         QWidgetPrivate *wd = w->d_func();
       
  1248 
       
  1249         int flags = QWidgetPrivate::DrawRecursive;
       
  1250         // Scrolled and moved widgets must draw all children.
       
  1251         if (!wd->isScrolled && !wd->isMoved)
       
  1252             flags |= QWidgetPrivate::DontDrawOpaqueChildren;
       
  1253         if (w == tlw)
       
  1254             flags |= QWidgetPrivate::DrawAsRoot;
       
  1255 
       
  1256         QRegion toBePainted(wd->dirty);
       
  1257         resetWidget(w);
       
  1258 
       
  1259 #ifdef Q_BACKINGSTORE_SUBSURFACES
       
  1260         QWindowSurface *subSurface = w->windowSurface();
       
  1261         BeginPaintInfo beginPaintInfo;
       
  1262         beginPaint(toBePainted, w, subSurface, &beginPaintInfo, false);
       
  1263         if (beginPaintInfo.nothingToPaint)
       
  1264             continue;
       
  1265 
       
  1266         if (beginPaintInfo.windowSurfaceRecreated) {
       
  1267             // Eep the window surface has changed. The old one may have been
       
  1268             // deleted, in which case we will segfault on the call to
       
  1269             // painterOffset() below. Use the new window surface instead.
       
  1270             subSurface = w->windowSurface();
       
  1271         }
       
  1272 
       
  1273         QPoint offset(tlwOffset);
       
  1274         if (subSurface == windowSurface)
       
  1275             offset += w->mapTo(tlw, QPoint());
       
  1276         else
       
  1277             offset = static_cast<QWSWindowSurface*>(subSurface)->painterOffset();
       
  1278         wd->drawWidget(subSurface->paintDevice(), toBePainted, offset, flags, 0, this);
       
  1279 
       
  1280         endPaint(toBePainted, subSurface, &beginPaintInfo);
       
  1281 #else
       
  1282         QPoint offset(tlwOffset);
       
  1283         if (w != tlw)
       
  1284             offset += w->mapTo(tlw, QPoint());
       
  1285         wd->drawWidget(windowSurface->paintDevice(), toBePainted, offset, flags, 0, this);
       
  1286 #endif
       
  1287     }
       
  1288 
       
  1289     // Paint the rest with composition.
       
  1290 #ifndef Q_BACKINGSTORE_SUBSURFACES
       
  1291     if (repaintAllWidgets || !dirtyCopy.isEmpty()) {
       
  1292         const int flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive;
       
  1293         tlw->d_func()->drawWidget(windowSurface->paintDevice(), dirtyCopy, tlwOffset, flags, 0, this);
       
  1294     }
       
  1295 
       
  1296     endPaint(toClean, windowSurface, &beginPaintInfo);
       
  1297 #else
       
  1298     if (!repaintAllWidgets && dirtyCopy.isEmpty())
       
  1299         return; // Nothing more to paint.
       
  1300 
       
  1301     QList<QWindowSurface *> surfaceList(subSurfaces);
       
  1302     surfaceList.prepend(windowSurface);
       
  1303     const QRect dirtyBoundingRect(dirtyCopy.boundingRect());
       
  1304 
       
  1305     // Loop through all window surfaces (incl. the top-level surface) and
       
  1306     // repaint those intersecting with the bounding rect of the dirty region.
       
  1307     for (int i = 0; i < surfaceList.size(); ++i) {
       
  1308         QWindowSurface *subSurface = surfaceList.at(i);
       
  1309         QWidget *w = subSurface->window();
       
  1310         QWidgetPrivate *wd = w->d_func();
       
  1311 
       
  1312         const QRect clipRect = wd->clipRect().translated(w->mapTo(tlw, QPoint()));
       
  1313         if (!qRectIntersects(dirtyBoundingRect, clipRect))
       
  1314             continue;
       
  1315 
       
  1316         toClean = dirtyCopy;
       
  1317         BeginPaintInfo beginPaintInfo;
       
  1318         beginPaint(toClean, w, subSurface, &beginPaintInfo);
       
  1319         if (beginPaintInfo.nothingToPaint)
       
  1320             continue;
       
  1321 
       
  1322         if (beginPaintInfo.windowSurfaceRecreated) {
       
  1323             // Eep the window surface has changed. The old one may have been
       
  1324             // deleted, in which case we will segfault on the call to
       
  1325             // painterOffset() below. Use the new window surface instead.
       
  1326             subSurface = w->windowSurface();
       
  1327         }
       
  1328 
       
  1329         int flags = QWidgetPrivate::DrawRecursive;
       
  1330         if (w == tlw)
       
  1331             flags |= QWidgetPrivate::DrawAsRoot;
       
  1332         const QPoint painterOffset = static_cast<QWSWindowSurface*>(subSurface)->painterOffset();
       
  1333         wd->drawWidget(subSurface->paintDevice(), toClean, painterOffset, flags, 0, this);
       
  1334 
       
  1335         endPaint(toClean, subSurface, &beginPaintInfo);
       
  1336     }
       
  1337 #endif
       
  1338 }
       
  1339 
       
  1340 /*!
       
  1341     Flushes the contents of the backing store into the top-level widget.
       
  1342     If the \a widget is non-zero, the content is flushed to the \a widget.
       
  1343     If the \a surface is non-zero, the content of the \a surface is flushed.
       
  1344 */
       
  1345 void QWidgetBackingStore::flush(QWidget *widget, QWindowSurface *surface)
       
  1346 {
       
  1347 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER)
       
  1348     paintWindowDecoration();
       
  1349 #endif
       
  1350 
       
  1351     if (!dirtyOnScreen.isEmpty()) {
       
  1352         QWidget *target = widget ? widget : tlw;
       
  1353         QWindowSurface *source = surface ? surface : windowSurface;
       
  1354         qt_flush(target, dirtyOnScreen, source, tlw, tlwOffset);
       
  1355         dirtyOnScreen = QRegion();
       
  1356     }
       
  1357 
       
  1358     if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty())
       
  1359         return;
       
  1360 
       
  1361     for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) {
       
  1362         QWidget *w = dirtyOnScreenWidgets->at(i);
       
  1363         QWidgetPrivate *wd = w->d_func();
       
  1364         Q_ASSERT(wd->needsFlush);
       
  1365         qt_flush(w, *wd->needsFlush, windowSurface, tlw, tlwOffset);
       
  1366         *wd->needsFlush = QRegion();
       
  1367     }
       
  1368     dirtyOnScreenWidgets->clear();
       
  1369 }
       
  1370 
       
  1371 static inline bool discardInvalidateBufferRequest(QWidget *widget, QTLWExtra *tlwExtra)
       
  1372 {
       
  1373     Q_ASSERT(widget);
       
  1374     if (QApplication::closingDown())
       
  1375         return true;
       
  1376 
       
  1377     if (!tlwExtra || tlwExtra->inTopLevelResize || !tlwExtra->backingStore)
       
  1378         return true;
       
  1379 
       
  1380     if (!widget->isVisible() || !widget->updatesEnabled())
       
  1381         return true;
       
  1382 
       
  1383     return false;
       
  1384 }
       
  1385 
       
  1386 /*!
       
  1387     Invalidates the buffer when the widget is resized.
       
  1388     Static areas are never invalidated unless absolutely needed.
       
  1389 */
       
  1390 void QWidgetPrivate::invalidateBuffer_resizeHelper(const QPoint &oldPos, const QSize &oldSize)
       
  1391 {
       
  1392     Q_Q(QWidget);
       
  1393     Q_ASSERT(!q->isWindow());
       
  1394     Q_ASSERT(q->parentWidget());
       
  1395 
       
  1396     const bool staticContents = q->testAttribute(Qt::WA_StaticContents);
       
  1397     const bool sizeDecreased = (data.crect.width() < oldSize.width())
       
  1398                                || (data.crect.height() < oldSize.height());
       
  1399 
       
  1400     const QPoint offset(data.crect.x() - oldPos.x(), data.crect.y() - oldPos.y());
       
  1401     const bool parentAreaExposed = !offset.isNull() || sizeDecreased;
       
  1402     const QRect newWidgetRect(q->rect());
       
  1403     const QRect oldWidgetRect(0, 0, oldSize.width(), oldSize.height());
       
  1404 
       
  1405     if (!staticContents || graphicsEffect) {
       
  1406         QRegion staticChildren;
       
  1407         QWidgetBackingStore *bs = 0;
       
  1408         if (offset.isNull() && (bs = maybeBackingStore()))
       
  1409             staticChildren = bs->staticContents(q, oldWidgetRect);
       
  1410         const bool hasStaticChildren = !staticChildren.isEmpty();
       
  1411 
       
  1412         if (hasStaticChildren) {
       
  1413             QRegion dirty(newWidgetRect);
       
  1414             dirty -= staticChildren;
       
  1415             invalidateBuffer(dirty);
       
  1416         } else {
       
  1417             // Entire widget needs repaint.
       
  1418             invalidateBuffer(newWidgetRect);
       
  1419         }
       
  1420 
       
  1421         if (!parentAreaExposed)
       
  1422             return;
       
  1423 
       
  1424         // Invalidate newly exposed area of the parent.
       
  1425         if (!graphicsEffect && extra && extra->hasMask) {
       
  1426             QRegion parentExpose(extra->mask.translated(oldPos));
       
  1427             parentExpose &= QRect(oldPos, oldSize);
       
  1428             if (hasStaticChildren)
       
  1429                 parentExpose -= data.crect; // Offset is unchanged, safe to do this.
       
  1430             q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
       
  1431         } else {
       
  1432             if (hasStaticChildren && !graphicsEffect) {
       
  1433                 QRegion parentExpose(QRect(oldPos, oldSize));
       
  1434                 parentExpose -= data.crect; // Offset is unchanged, safe to do this.
       
  1435                 q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
       
  1436             } else {
       
  1437                 q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(QRect(oldPos, oldSize)));
       
  1438             }
       
  1439         }
       
  1440         return;
       
  1441     }
       
  1442 
       
  1443     // Move static content to its new position.
       
  1444     if (!offset.isNull()) {
       
  1445         if (sizeDecreased) {
       
  1446             const QSize minSize(qMin(oldSize.width(), data.crect.width()),
       
  1447                                 qMin(oldSize.height(), data.crect.height()));
       
  1448             moveRect(QRect(oldPos, minSize), offset.x(), offset.y());
       
  1449         } else {
       
  1450             moveRect(QRect(oldPos, oldSize), offset.x(), offset.y());
       
  1451         }
       
  1452     }
       
  1453 
       
  1454     // Invalidate newly visible area of the widget.
       
  1455     if (!sizeDecreased || !oldWidgetRect.contains(newWidgetRect)) {
       
  1456         QRegion newVisible(newWidgetRect);
       
  1457         newVisible -= oldWidgetRect;
       
  1458         invalidateBuffer(newVisible);
       
  1459     }
       
  1460 
       
  1461     if (!parentAreaExposed)
       
  1462         return;
       
  1463 
       
  1464     // Invalidate newly exposed area of the parent.
       
  1465     const QRect oldRect(oldPos, oldSize);
       
  1466     if (extra && extra->hasMask) {
       
  1467         QRegion parentExpose(oldRect);
       
  1468         parentExpose &= extra->mask.translated(oldPos);
       
  1469         parentExpose -= (extra->mask.translated(data.crect.topLeft()) & data.crect);
       
  1470         q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
       
  1471     } else {
       
  1472         QRegion parentExpose(oldRect);
       
  1473         parentExpose -= data.crect;
       
  1474         q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
       
  1475     }
       
  1476 }
       
  1477 
       
  1478 /*!
       
  1479     Invalidates the \a rgn (in widget's coordinates) of the backing store, i.e.
       
  1480     all widgets intersecting with the region will be repainted when the backing store
       
  1481     is synced.
       
  1482 
       
  1483     ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
       
  1484 */
       
  1485 void QWidgetPrivate::invalidateBuffer(const QRegion &rgn)
       
  1486 {
       
  1487     Q_Q(QWidget);
       
  1488 
       
  1489     QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
       
  1490     if (discardInvalidateBufferRequest(q, tlwExtra) || rgn.isEmpty())
       
  1491         return;
       
  1492 
       
  1493     QRegion wrgn(rgn);
       
  1494     wrgn &= clipRect();
       
  1495     if (!graphicsEffect && extra && extra->hasMask)
       
  1496         wrgn &= extra->mask;
       
  1497     if (wrgn.isEmpty())
       
  1498         return;
       
  1499 
       
  1500     tlwExtra->backingStore->markDirty(wrgn, q, false, true);
       
  1501 }
       
  1502 
       
  1503 /*!
       
  1504     This function is equivalent to calling invalidateBuffer(QRegion(rect), ...), but
       
  1505     is more efficient as it eliminates QRegion operations/allocations and can
       
  1506     use the rect more precisely for additional cut-offs.
       
  1507 
       
  1508     ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
       
  1509 */
       
  1510 void QWidgetPrivate::invalidateBuffer(const QRect &rect)
       
  1511 {
       
  1512     Q_Q(QWidget);
       
  1513 
       
  1514     QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
       
  1515     if (discardInvalidateBufferRequest(q, tlwExtra) || rect.isEmpty())
       
  1516         return;
       
  1517 
       
  1518     QRect wRect(rect);
       
  1519     wRect &= clipRect();
       
  1520     if (wRect.isEmpty())
       
  1521         return;
       
  1522 
       
  1523     if (graphicsEffect || !extra || !extra->hasMask) {
       
  1524         tlwExtra->backingStore->markDirty(wRect, q, false, true);
       
  1525         return;
       
  1526     }
       
  1527 
       
  1528     QRegion wRgn(extra->mask);
       
  1529     wRgn &= wRect;
       
  1530     if (wRgn.isEmpty())
       
  1531         return;
       
  1532 
       
  1533     tlwExtra->backingStore->markDirty(wRgn, q, false, true);
       
  1534 }
       
  1535 
       
  1536 void QWidgetPrivate::repaint_sys(const QRegion &rgn)
       
  1537 {
       
  1538     if (data.in_destructor)
       
  1539         return;
       
  1540 
       
  1541     Q_Q(QWidget);
       
  1542     if (q->testAttribute(Qt::WA_StaticContents)) {
       
  1543         if (!extra)
       
  1544             createExtra();
       
  1545         extra->staticContentsSize = data.crect.size();
       
  1546     }
       
  1547 
       
  1548     QPaintEngine *engine = q->paintEngine();
       
  1549     // QGLWidget does not support partial updates if:
       
  1550     // 1) The context is double buffered
       
  1551     // 2) The context is single buffered and auto-fill background is enabled.
       
  1552     const bool noPartialUpdateSupport = (engine && (engine->type() == QPaintEngine::OpenGL
       
  1553                                                 || engine->type() == QPaintEngine::OpenGL2))
       
  1554                                         && (usesDoubleBufferedGLContext || q->autoFillBackground());
       
  1555     QRegion toBePainted(noPartialUpdateSupport ? q->rect() : rgn);
       
  1556 
       
  1557 #ifdef Q_WS_MAC
       
  1558     // No difference between update() and repaint() on the Mac.
       
  1559     update_sys(toBePainted);
       
  1560     return;
       
  1561 #endif
       
  1562 
       
  1563     toBePainted &= clipRect();
       
  1564     clipToEffectiveMask(toBePainted);
       
  1565     if (toBePainted.isEmpty())
       
  1566         return; // Nothing to repaint.
       
  1567 
       
  1568 #ifndef QT_NO_PAINT_DEBUG
       
  1569     bool flushed = QWidgetBackingStore::flushPaint(q, toBePainted);
       
  1570 #endif
       
  1571 
       
  1572     drawWidget(q, toBePainted, QPoint(), QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawPaintOnScreen, 0);
       
  1573 
       
  1574 #ifndef QT_NO_PAINT_DEBUG
       
  1575     if (flushed)
       
  1576         QWidgetBackingStore::unflushPaint(q, toBePainted);
       
  1577 #endif
       
  1578 
       
  1579     if (!q->testAttribute(Qt::WA_PaintOutsidePaintEvent) && q->paintingActive())
       
  1580         qWarning("QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent");
       
  1581 }
       
  1582 
       
  1583 
       
  1584 QT_END_NAMESPACE