src/gui/painting/qbackingstore.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtGui module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 #include <qglobal.h>
00024 #include <qapplication.h>
00025 #ifdef Q_WS_WIN
00026 # include "qt_windows.h"
00027 # include <private/qpaintengine_raster_p.h>
00028 #endif
00029 #include "qbackingstore_p.h"
00030 #include "private/qwidget_p.h"
00031 #include <qdebug.h>
00032 #include <qstack.h>
00033 #include <qevent.h>
00034 #include <qabstractscrollarea.h>
00035 #include "private/qabstractscrollarea_p.h"
00036 #ifdef Q_WS_X11
00037 # include "private/qt_x11_p.h"
00038 #endif
00039 
00040 #ifdef Q_WS_QWS
00041 #include <qscreen_qws.h>
00042 #include <qwsdisplay_qws.h>
00043 #include <qapplication.h>
00044 #include <qwsmanager_qws.h>
00045 #include <private/qwsmanager_p.h>
00046 #include <unistd.h>
00047 #endif
00048 
00049 #include "qwindowsurface_raster_p.h"
00050 #ifdef Q_WS_X11
00051 #include "qwindowsurface_x11_p.h"
00052 #elif defined(Q_WS_QWS)
00053 #include "qwindowsurface_qws_p.h"
00054 #endif
00055 
00056 /*****************************************************************************
00057   Top Level Window backing store
00058  *****************************************************************************/
00059 
00060 extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); // qapplication_xxx.cpp
00061 
00062 #ifndef Q_WS_QWS
00063 static bool qt_enable_backingstore = true;
00064 #endif
00065 #ifdef Q_WS_X11
00066 // for compatibility with Qt 4.0
00067 Q_GUI_EXPORT void qt_x11_set_global_double_buffer(bool enable)
00068 {
00069     qt_enable_backingstore = enable;
00070 }
00071 #endif
00072 
00073 bool QWidgetBackingStore::paintOnScreen(QWidget *w)
00074 {
00075 #if defined(Q_WS_QWS) || defined(Q_WS_MAC)
00076     Q_UNUSED(w);
00077     return false;
00078 #elif  defined(QT_NO_BACKINGSTORE)
00079     Q_UNUSED(w);
00080     return true;
00081 #else
00082     if (w && (w->testAttribute(Qt::WA_PaintOnScreen) || !w->isWindow() && w->window()->testAttribute(Qt::WA_PaintOnScreen)))
00083         return true;
00084 
00085     // sanity check for overlarge toplevels. Better: store at least screen size and move offset.
00086     if (w && w->isWindow() && (w->width() > 4096  || w->height() > 4096))
00087         return true;
00088 
00089     static signed char checked_env = -1;
00090     if(checked_env == -1)
00091         checked_env = (qgetenv("QT_ONSCREEN_PAINT") == "1") ? 1 : 0;
00092 
00093     return checked_env == 1 || !qt_enable_backingstore;
00094 #endif
00095 }
00096 
00097 #ifdef Q_WS_QWS
00098 static void qt_showYellowThing(QWidget *widget, const QRegion &rgn, int msec, bool)
00099 {
00100     Q_UNUSED(widget);
00101 
00102     static QWSYellowSurface surface(true);
00103     surface.setDelay(msec);
00104     surface.flush(widget, rgn, QPoint());
00105 }
00106 
00107 #else
00108 static void qt_showYellowThing(QWidget *widget, const QRegion &toBePainted, int msec, bool unclipped)
00109 {
00110     //flags to fool painter
00111     bool paintUnclipped = widget->testAttribute(Qt::WA_PaintUnclipped);
00112     if (unclipped && !QWidgetBackingStore::paintOnScreen(widget))
00113         widget->setAttribute(Qt::WA_PaintUnclipped);
00114 
00115     bool setFlag = !widget->testAttribute(Qt::WA_WState_InPaintEvent);
00116     if(setFlag)
00117         widget->setAttribute(Qt::WA_WState_InPaintEvent);
00118 
00119 
00120     static int i = 0;
00121 
00122     //setup the engine
00123     QPaintEngine *pe = widget->paintEngine();
00124     if (pe) {
00125         pe->setSystemClip(toBePainted);
00126         {
00127             QPainter p(widget);
00128             p.setClipRegion(toBePainted);
00129 
00130             switch (i) {
00131             case 0:
00132                 p.fillRect(widget->rect(), QColor(255,255,0));
00133                 break;
00134             case 1:
00135                 p.fillRect(widget->rect(), QColor(255,200,55));
00136                 break;
00137             case 2:
00138                 p.fillRect(widget->rect(), QColor(200,255,55));
00139                 break;
00140             case 3:
00141                 p.fillRect(widget->rect(), QColor(200,200,0));
00142                 break;
00143             }
00144             i = (i+1) & 3;
00145             p.end();
00146         }
00147     }
00148 
00149     if(setFlag)
00150         widget->setAttribute(Qt::WA_WState_InPaintEvent, false);
00151 
00152     //restore
00153     widget->setAttribute(Qt::WA_PaintUnclipped, paintUnclipped);
00154 
00155     if (pe) {
00156         pe->setSystemClip(QRegion());
00157         //flush
00158         if (pe->type() == QPaintEngine::Raster) {
00159             QRasterPaintEngine *rpe = static_cast<QRasterPaintEngine *>(pe);
00160             rpe->flush(widget, QPoint());
00161         }
00162     }
00163 
00164     QApplication::syncX();
00165 
00166 #if defined(Q_OS_UNIX)
00167     ::usleep(1000*msec);
00168 #elif defined(Q_OS_WIN)
00169     ::Sleep(msec);
00170 #endif
00171 
00172 }
00173 #endif
00174 
00175 static bool qt_flushPaint(QWidget *widget, const QRegion &toBePainted)
00176 {
00177     static int checked_env = -1;
00178     if(checked_env == -1)
00179         checked_env = qgetenv("QT_FLUSH_PAINT").toInt();
00180 
00181     if (checked_env == 0)
00182         return false;
00183 
00184     qt_showYellowThing(widget, toBePainted, checked_env*10, true);
00185 
00186     return true;
00187 }
00188 
00189 static void qt_unflushPaint(QWidget *widget, const QRegion &rgn)
00190 {
00191     if (!QWidgetBackingStore::paintOnScreen(widget))
00192         QWidgetBackingStore::copyToScreen(widget, rgn);
00193 }
00194 
00195 #if !defined(Q_WS_QWS)
00196 static bool qt_flushUpdate(QWidget *widget, const QRegion &rgn)
00197 {
00198     static int checked_env = -1;
00199     if(checked_env == -1) {
00200         checked_env = qgetenv("QT_FLUSH_UPDATE").toInt();
00201     }
00202 
00203     if (checked_env == 0)
00204         return false;
00205 
00206     qt_showYellowThing(widget, rgn, checked_env*10, false);
00207 
00208     return true;
00209 }
00210 #endif
00211 
00212 void qt_syncBackingStore(QRegion rgn, QWidget *widget, bool recursive)
00213 {
00214     if (!QWidgetBackingStore::paintOnScreen(widget)) {
00215         if (QWidgetBackingStore *bs = widget->d_func()->maybeBackingStore())
00216             bs->cleanRegion(rgn, widget, recursive);
00217     } else {
00218         widget->repaint(rgn);
00219     }
00220 }
00221 void qt_syncBackingStore(QRegion rgn, QWidget *widget)
00222 {
00223     qt_syncBackingStore(rgn, widget, false);
00224 }
00225 
00226 QWindowSurface *qt_default_window_surface(QWidget *widget)
00227 {
00228 #ifdef Q_WS_WIN
00229     return new QRasterWindowSurface(widget);
00230 #elif defined(Q_WS_X11)
00231     return new QX11WindowSurface(widget);
00232 #elif defined(Q_WS_QWS)
00233     if (widget->windowType() == Qt::Desktop)
00234         return 0;
00235     return qt_screen->createSurface(widget);
00236 #else
00237     Q_UNUSED(widget);
00238     return 0;
00239 #endif
00240 }
00241 
00242 #ifdef Q_WS_WIN
00243 
00244 /*
00245    Used by QETWidget::translatePaintEvent and expects rgn to be in
00246    windowing system coordinates.
00247  */
00248 
00249 void QWidgetBackingStore::blitToScreen(const QRegion &rgn, QWidget *widget)
00250 {
00251     QWidget *tlw = widget->window();
00252     if (!widget->isVisible() || !tlw->testAttribute(Qt::WA_Mapped) || rgn.isEmpty())
00253         return;
00254 
00255     if (!QWidgetBackingStore::paintOnScreen(widget)) {
00256         QWidgetBackingStore *bs = tlw->d_func()->topData()->backingStore;
00257 
00258         bs->windowSurface->flush(widget, rgn, widget->mapTo(tlw, QPoint(0, 0)));
00259     }
00260 }
00261 #endif
00262 
00263 #if defined(Q_WS_X11)
00264 void qt_syncBackingStore(QWidget *widget)
00265 {
00266     // dirtyOnScreen may get out of sync when widget is scrolled or moved
00267     widget->d_func()->dirtyOnScreen &= widget->d_func()->clipRect();
00268 
00269     const QRegion dirty =  widget->d_func()->dirtyOnScreen;
00270     QWidget *tlw = widget->window();
00271     if (!QWidgetBackingStore::paintOnScreen(widget)) {
00272         QWidgetBackingStore *bs = tlw->d_func()->topData()->backingStore;
00273         bs->cleanRegion(dirty, widget);
00274     } else {
00275         widget->repaint(dirty);
00276     }
00277 }
00278 #elif defined(Q_WS_QWS)
00279 void qt_syncBackingStore(QWidget *widget)
00280 {
00281     QWidget *tlw = widget->window();
00282     QTLWExtra *topData = tlw->d_func()->topData();
00283 
00284     QWidgetBackingStore *bs = topData->backingStore;
00285     QWSWindowSurface *surface = 0;
00286     if(bs)
00287         surface = static_cast<QWSWindowSurface*>(bs->windowSurface);
00288     else
00289         qWarning("request to sync backing store of widget %p, "
00290                  "which does not have its backing store defined yet",
00291                  (void*)widget);
00292 
00293     QRegion toClean;
00294 
00295     if (surface)
00296         toClean = surface->dirtyRegion();
00297     if (!toClean.isEmpty())
00298         topData->backingStore->cleanRegion(toClean, tlw);
00299 }
00300 #endif
00301 
00302 /*
00303    A version of QRect::intersects() that does not normalize the rects.
00304 */
00305 static inline bool qRectIntersects(const QRect &r1, const QRect &r2)
00306 {
00307     return (qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right()) &&
00308              qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom()));
00309 }
00310 
00311 QWidgetBackingStore::QWidgetBackingStore(QWidget *t) : tlw(t)
00312 {
00313     windowSurface = tlw->windowSurface();
00314     if (!windowSurface)
00315         windowSurface = qt_default_window_surface(t);
00316 }
00317 
00318 QWidgetBackingStore::~QWidgetBackingStore()
00319 {
00320     if (!tlw->windowSurface())
00321         delete windowSurface;
00322 }
00323 
00324 /*
00325   Widget's coordinate system
00326   move whole rect by dx,dy
00327   rect must be valid
00328   doesn't generate any updates
00329 */
00330 void QWidgetBackingStore::bltRect(const QRect &rect, int dx, int dy, QWidget *widget)
00331 {
00332     QPoint pos(widget->mapTo(tlw, rect.topLeft()));
00333 
00334 #ifdef Q_WS_QWS
00335     QWSWindowSurface *surface = static_cast<QWSWindowSurface*>(windowSurface);
00336     if (!surface)
00337         return;
00338 
00339     // clip to surface region
00340     const QRegion clip = surface->clipRegion();
00341     QRegion r = QRect(pos, rect.size());
00342     r = (r & clip).translated(dx, dy) & clip;
00343     r.translate(-dx, -dy);
00344 
00345     windowSurface->scroll(r.translated(topLevelOffset()), dx, dy);
00346 #else
00347     windowSurface->scroll(QRect(pos, rect.size()), dx, dy);
00348 #endif
00349 }
00350 
00351 
00352 //parent's coordinates; move whole rect; update parent and widget
00353 //assume the screen blt has already been done, so we don't need to refresh that part
00354 void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy)
00355 {
00356     Q_Q(QWidget);
00357     if (!q->isVisible())
00358         return;
00359 
00360     QWidget *tlw = q->window();
00361     QTLWExtra* x = tlw->d_func()->topData();
00362 
00363 
00364     static int accelEnv = -1;
00365     if (accelEnv == -1) {
00366         accelEnv = qgetenv("QT_NO_FAST_MOVE").toInt() == 0;
00367     }
00368 
00369     QWidget *pw = q->parentWidget();
00370     QWidgetPrivate *pd = pw->d_func();
00371     QRect clipR = pd->clipRect();
00372     QRect newRect = rect.translated(dx,dy);
00373 
00374     QRect destRect = rect.intersected(clipR);
00375     if (destRect.isValid())
00376         destRect = destRect.translated(dx,dy).intersected(clipR);
00377     QRect sourceRect = destRect.translated(-dx, -dy);
00378 
00379     bool accelerateMove = accelEnv &&  isOpaque() && !isOverlapped(sourceRect)
00380         && !isOverlapped(destRect);
00381 
00382     if (!accelerateMove) {
00383         QRegion parentR(rect & clipR);
00384         if (q->mask().isEmpty()) {
00385             parentR -= newRect;
00386         } else {
00387             // invalidateBuffer() excludes anything outside the mask
00388             parentR += newRect & clipR;
00389         }
00390         pd->invalidateBuffer(parentR);
00391         invalidateBuffer((newRect & clipR).translated(-data.crect.topLeft()));
00392     } else {
00393         QWidgetBackingStore *wbs = x->backingStore;
00394         if (sourceRect.isValid())
00395             wbs->bltRect(sourceRect, dx, dy, pw);
00396 
00397 
00398         QRegion childExpose = newRect & clipR;
00399         childExpose -= destRect;
00400 
00401         QPoint toplevelOffset = pw->mapTo(tlw, QPoint());
00402         QRect newDirty = (wbs->dirty & sourceRect.translated(toplevelOffset)).boundingRect().translated(QPoint(dx,dy) - toplevelOffset);
00403         childExpose += newDirty;
00404 
00405         childExpose.translate(-data.crect.topLeft());
00406         invalidateBuffer(childExpose);
00407 
00408         QRegion parentExpose = rect & clipR;
00409         parentExpose -= newRect;
00410         if (!q->mask().isEmpty()) {
00411             parentExpose += QRegion(newRect) - q->mask().translated(data.crect.topLeft());
00412         }
00413         pd->invalidateBuffer(parentExpose);
00414 #ifdef Q_WS_QWS
00415         //QWS does not have native child widgets: copy everything to screen, just like scrollRect()
00416         pd->dirtyWidget_sys(QRegion(sourceRect)+destRect);
00417 #endif
00418     }
00419 }
00420 
00421 //widget's coordinates; scroll within rect;  only update widget
00422 void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy)
00423 {
00424     Q_Q(QWidget);
00425     QWidget *tlw = q->window();
00426     QTLWExtra* x = tlw->d_func()->topData();
00427     QWidgetBackingStore *wbs = x->backingStore;
00428 
00429     static int accelEnv = -1;
00430     if (accelEnv == -1) {
00431         accelEnv = qgetenv("QT_NO_FAST_SCROLL").toInt() == 0;
00432     }
00433 
00434     bool accelerateScroll = accelEnv &&  isOpaque()  && !isOverlapped(data.crect);
00435 
00436 #if defined(Q_WS_QWS)
00437     QWSWindowSurface *surface;
00438     surface = static_cast<QWSWindowSurface*>(wbs->windowSurface);
00439 
00440     if (accelerateScroll && !surface->isBuffered()) {
00441         const QRegion surfaceClip = surface->clipRegion();
00442         const QRegion outsideClip = QRegion(rect) - surfaceClip;
00443         if (!outsideClip.isEmpty()) {
00444             const QVector<QRect> clipped = (surfaceClip & rect).rects();
00445             if (clipped.size() < 8) {
00446                 for (int i = 0; i < clipped.size(); ++i)
00447                     scrollRect(clipped.at(i), dx, dy);
00448                 return;
00449             } else {
00450                 accelerateScroll = false;
00451             }
00452         }
00453     }
00454 #endif // Q_WS_QWS
00455 
00456     if (!accelerateScroll) {
00457         invalidateBuffer(rect);
00458     } else {
00459         QRect scrollRect = rect & clipRect();
00460 
00461         QRect destRect = scrollRect.isValid() ? scrollRect.translated(dx,dy).intersected(scrollRect) : QRect();
00462         QRect sourceRect = destRect.translated(-dx, -dy);
00463 
00464         QPoint toplevelOffset = q->mapTo(tlw, QPoint());
00465 
00466 
00467         if (sourceRect.isValid())
00468             wbs->bltRect(sourceRect, dx, dy, q);
00469 
00470         QRegion childExpose = scrollRect;
00471         childExpose -= destRect;
00472 //        childExpose += (wbs->dirty & sourceRect.translated(toplevelOffset)).boundingRect().translated(QPoint(dx,dy) - toplevelOffset);
00473         QRect newDirty = (wbs->dirty & sourceRect.translated(toplevelOffset)).boundingRect().translated(QPoint(dx,dy) - toplevelOffset);
00474 //         qDebug() << "scrollRect" << q << rect << dx << dy << "dirty" << wbs->dirty << "newDirty" << newDirty;
00475         childExpose += newDirty;
00476         invalidateBuffer(childExpose);
00477 
00478         // Instead of using native scroll-on-screen, we copy from
00479         // backingstore, giving only one screen update for each
00480         // scroll, and a solid appearance
00481         dirtyWidget_sys(rect);
00482     }
00483 }
00484 
00485 void QWidgetBackingStore::dirtyRegion(const QRegion &rgn, QWidget *widget)
00486 {
00487     QRegion wrgn(rgn);
00488     Q_ASSERT(widget->window() == tlw);
00489     if(!widget->isVisible() || !widget->updatesEnabled())
00490         return;
00491     wrgn &= widget->d_func()->clipRect();
00492     if (!widget->mask().isEmpty())
00493         wrgn &= widget->mask();
00494 #ifndef Q_WS_QWS
00495     widget->d_func()->dirtyWidget_sys(wrgn);
00496 #endif
00497     wrgn.translate(widget->mapTo(tlw, QPoint(0, 0)));
00498     dirty += wrgn;
00499 #ifdef Q_WS_QWS
00500     tlw->d_func()->dirtyWidget_sys(wrgn); //optimization: don't translate twice
00501 #endif
00502 }
00503 
00504 
00505 void QWidgetBackingStore::copyToScreen(QWidget *widget, const QRegion &rgn)
00506 {
00507     QWidget *tlw = widget->window();
00508     QTLWExtra *topextra = tlw->d_func()->extra->topextra;
00509     QPoint offset = widget->mapTo(tlw, QPoint());
00510     topextra->backingStore->copyToScreen(rgn, widget, offset, false);
00511 }
00512 
00520 void QWidgetBackingStore::copyToScreen(const QRegion &rgn, QWidget *widget, const QPoint &offset, bool recursive)
00521 {
00522     if (rgn.isEmpty())
00523         return;
00524     Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
00525 #ifdef Q_WS_QWS
00526     Q_UNUSED(recursive);
00527     windowSurface->flush(widget, rgn, offset);
00528 #else
00529     if (!QWidgetBackingStore::paintOnScreen(widget)) {
00530         widget->d_func()->cleanWidget_sys(rgn);
00531 
00532         qt_flushUpdate(widget, rgn);
00533 
00534         QPoint wOffset = widget->data->wrect.topLeft();
00535         windowSurface->flush(widget, rgn, offset);
00536     }
00537 
00538     if(recursive) {
00539         const QObjectList children = widget->children();
00540         for(int i = 0; i < children.size(); ++i) {
00541             if(QWidget *child = qobject_cast<QWidget*>(children.at(i))) {
00542                 if(!child->isWindow() && child->isVisible()) {
00543                     if (qRectIntersects(rgn.boundingRect().translated(-child->pos()), child->rect())) {
00544                         QRegion childRegion(rgn);
00545                         childRegion.translate(-child->pos());
00546                         childRegion &= child->d_func()->clipRect();
00547                         if(!childRegion.isEmpty())
00548                             copyToScreen(childRegion, child, offset+child->pos(), recursive);
00549                     }
00550                 }
00551             }
00552         }
00553     }
00554 #endif
00555 }
00556 
00557 void QWidgetBackingStore::cleanRegion(const QRegion &rgn, QWidget *widget, bool recursiveCopyToScreen)
00558 {
00559     if (!widget->isVisible() || !widget->updatesEnabled() || !tlw->testAttribute(Qt::WA_Mapped) || rgn.isEmpty())
00560         return;
00561 
00562     if(!QWidgetBackingStore::paintOnScreen(widget)) {
00563         QRegion toClean;
00564 #if defined(Q_WS_QWS)
00565         QRect tlwRect = tlw->frameGeometry();
00566 #else
00567         QRect tlwRect = tlw->geometry();
00568 #endif
00569 
00570 #ifdef Q_WS_QWS
00571         if (!static_cast<QWSWindowSurface*>(windowSurface)->isValidFor(tlw)) {
00572             delete windowSurface;
00573             windowSurface = qt_default_window_surface(tlw);
00574         }
00575 #endif
00576         if (windowSurface->geometry() != tlwRect) {
00577             windowSurface->setGeometry(tlwRect);
00578             toClean = QRect(QPoint(0, 0), tlwRect.size());
00579             recursiveCopyToScreen = true;
00580         } else {
00581             toClean = dirty;
00582         }
00583 #ifdef Q_WS_QWS
00584         tlwOffset = static_cast<QWSWindowSurface*>(windowSurface)->painterOffset();
00585 #endif
00586          // ### move into prerender step
00587 
00588 #if defined(Q_WS_QWS)
00589         const QRegion clip = static_cast<QWSWindowSurface*>(windowSurface)->clipRegion();
00590         if (!clip.isEmpty())
00591             toClean &= clip;
00592 #endif
00593 
00594         if(!toClean.isEmpty()) {
00595             dirty -= toClean;
00596             if (tlw->updatesEnabled()) {
00597                 // Pre render config
00598                 windowSurface->paintDevice()->paintEngine()->setSystemClip(toClean);
00599                 windowSurface->beginPaint(toClean);
00600                 windowSurface->paintDevice()->paintEngine()->setSystemClip(QRegion());
00601 
00602                 tlw->d_func()->drawWidget(windowSurface->paintDevice(), toClean, tlwOffset);
00603 
00604                 // Drawing the overlay...
00605                 windowSurface->paintDevice()->paintEngine()->setSystemClip(toClean);
00606                 windowSurface->endPaint(toClean);
00607                 windowSurface->paintDevice()->paintEngine()->setSystemClip(QRegion());
00608             }
00609         }
00610 
00611         QRegion toFlush = rgn;
00612         if (recursiveCopyToScreen) {
00613             toFlush.translate(widget->mapTo(tlw, QPoint()));
00614             copyToScreen(toFlush, tlw, tlwOffset, recursiveCopyToScreen);
00615         } else {
00616 #ifdef Q_WS_X11
00617             toFlush += widget->d_func()->dirtyOnScreen;
00618 #endif
00619             copyToScreen(toFlush, widget, widget->mapTo(tlw, QPoint()), false);
00620         }
00621     }
00622 }
00623 
00624 #ifdef Q_WS_QWS
00625 void QWidgetBackingStore::releaseBuffer()
00626 {
00627     if (windowSurface)
00628         windowSurface->release();
00629 }
00630 #elif defined(Q_WS_WIN)
00631 void QWidgetBackingStore::releaseBuffer()
00632 {
00633     windowSurface->release();
00634 }
00635 #endif
00636 
00637 bool QWidgetBackingStore::isOpaque(const QWidget *widget)
00638 {
00639     return widget->d_func()->isOpaque();
00640 }
00641 
00642 
00643 void QWidgetBackingStore::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectList& siblings, int index, const QRegion &rgn,
00644                                                  const QPoint &offset, int flags)
00645 {
00646     QWidget *w = 0;
00647 
00648     do {
00649         QWidget *x =  qobject_cast<QWidget*>(siblings.at(index));
00650         if (x && !x->isWindow() && !x->isHidden() && qRectIntersects(rgn.boundingRect(), x->geometry())) {
00651             w = x;
00652             break;
00653         }
00654         --index;
00655     } while (index >= 0);
00656 
00657 
00658     if (!w)
00659         return;
00660 
00661     QWExtra *extra = w->d_func()->extraData();
00662 
00663     if (index > 0) {
00664         QRegion wr = rgn;
00665         if (isOpaque(w)) {
00666             if(!extra || extra->mask.isEmpty()) {
00667                 wr -= w->geometry();
00668             } else {
00669                 wr -= extra->mask.translated(w->pos());
00670             }
00671         }
00672         paintSiblingsRecursive(pdev, siblings, index - 1, wr, offset, flags);
00673     }
00674     if(w->updatesEnabled()) {
00675         QRegion wRegion(rgn & w->geometry());
00676         wRegion.translate(-w->pos());
00677 
00678         if(extra && !extra->mask.isEmpty())
00679             wRegion &= extra->mask;
00680         if(!wRegion.isEmpty())
00681             w->d_func()->drawWidget(pdev, wRegion, offset+w->pos(), flags);
00682     }
00683 }
00684 
00685 void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QPoint &offset, int flags)
00686 {
00687     Q_Q(QWidget);
00688     if (rgn.isEmpty())
00689         return;
00690 
00691     const bool asRoot = flags & DrawAsRoot;
00692     const bool alsoOnScreen = flags & DrawPaintOnScreen;
00693     const bool recursive = flags & DrawRecursive;
00694     const bool alsoInvisible = flags & DrawInvisible;
00695 
00696     QRegion toBePainted = rgn;
00697     if (asRoot && !alsoInvisible)
00698         toBePainted &= clipRect(); //(rgn & visibleRegion());
00699     subtractOpaqueChildren(toBePainted, q->rect(), QPoint());
00700 
00701     if (!toBePainted.isEmpty()) {
00702         bool onScreen = QWidgetBackingStore::paintOnScreen(q);
00703         if (!onScreen || alsoOnScreen) {
00704             //update the "in paint event" flag
00705             if (q->testAttribute(Qt::WA_WState_InPaintEvent))
00706                 qWarning("QWidget::repaint: Recursive repaint detected");
00707             q->setAttribute(Qt::WA_WState_InPaintEvent);
00708 
00709             //clip away the new area
00710             bool flushed = qt_flushPaint(q, toBePainted);
00711 
00712             QPaintEngine *paintEngine = pdev->paintEngine();
00713             if (paintEngine) {
00714                 QPainter::setRedirected(q, pdev, -offset);
00715 
00716                 QRegion wrgn = toBePainted;
00717                 wrgn.translate(offset);
00718                 paintEngine->setSystemRect(q->data->crect);
00719                 paintEngine->setSystemClip(wrgn);
00720 
00721                 //paint the background
00722                 if ((asRoot || q->autoFillBackground() || onScreen)
00723                     && !q->testAttribute(Qt::WA_OpaquePaintEvent)
00724                     && !q->testAttribute(Qt::WA_NoSystemBackground)) {
00725 
00726                     QPainter p(q);
00727                     QRect backgroundRect = toBePainted.boundingRect();
00728 
00729 #ifndef QT_NO_SCROLLAREA
00730                     if (QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(q->parent())) {
00731                         if (scrollArea->viewport() == q) {
00732                             QAbstractScrollAreaPrivate *priv = static_cast<QAbstractScrollAreaPrivate *>(static_cast<QWidget *>(scrollArea)->d_ptr);
00733                             const QPoint offset = priv->contentsOffset();
00734                             p.translate(-offset);
00735                             backgroundRect.translate(offset);
00736                         }
00737                     }
00738 #endif // QT_NO_SCROLLAREA
00739                     paintBackground(&p, backgroundRect, asRoot || onScreen);
00740                 }
00741                 if (q->testAttribute(Qt::WA_TintedBackground)
00742                     && !onScreen && !asRoot && !isOpaque() ) {
00743                     QPainter p(q);
00744                     QColor tint = q->palette().window().color();
00745                     tint.setAlphaF(.6);
00746                     p.fillRect(toBePainted.boundingRect(), tint);
00747                 }
00748             }
00749 
00750 #if 0
00751             qDebug() << "painting" << q << "opaque ==" << isOpaque();
00752             qDebug() << "clipping to" << toBePainted << "location == " << offset
00753                      << "geometry ==" << QRect(q->mapTo(q->window(), QPoint(0, 0)), q->size());
00754 #endif
00755 
00756             //actually send the paint event
00757             QPaintEvent e(toBePainted);
00758             qt_sendSpontaneousEvent(q, &e);
00759 
00760             //restore
00761             if (paintEngine) {
00762                 paintEngine->setSystemRect(QRect());
00763                 pdev->paintEngine()->setSystemClip(QRegion());
00764                 QPainter::restoreRedirected(q);
00765             }
00766             q->setAttribute(Qt::WA_WState_InPaintEvent, false);
00767             if(!q->testAttribute(Qt::WA_PaintOutsidePaintEvent) && q->paintingActive())
00768                 qWarning("QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent");
00769 
00770             if (flushed)
00771                 qt_unflushPaint(q, toBePainted);
00772         } else if(q->isWindow()) {
00773             if (pdev->paintEngine()) {
00774                 QPainter p(pdev);
00775                 p.setClipRegion(toBePainted);
00776                 const QBrush bg = q->palette().brush(QPalette::Window);
00777                 if (bg.style() == Qt::TexturePattern)
00778                     p.drawTiledPixmap(q->rect(), bg.texture());
00779                 else
00780                     p.fillRect(q->rect(), bg);
00781             }
00782         }
00783     }
00784 
00785     if (recursive) {
00786         const QObjectList children = q->children();
00787         if (!children.isEmpty())
00788             QWidgetBackingStore::paintSiblingsRecursive(pdev, children, children.size()-1, rgn, offset, flags & ~DrawAsRoot);
00789     }
00790 }
00791 
00792 /* cross-platform QWidget code */
00793 
00794 void QWidgetPrivate::invalidateBuffer(const QRegion &rgn)
00795 {
00796     if(qApp && qApp->closingDown())
00797         return;
00798     Q_Q(QWidget);
00799     if (QWidgetBackingStore *bs = maybeBackingStore())
00800         bs->dirtyRegion(rgn, q);
00801 }
00802 
00803 void QWidget::repaint(const QRegion& rgn)
00804 {
00805     if (testAttribute(Qt::WA_WState_ConfigPending)) {
00806         update(rgn);
00807         return;
00808     }
00809 
00810     if (!isVisible() || !updatesEnabled() || rgn.isEmpty())
00811         return;
00812     Q_D(QWidget);
00813     Q_ASSERT(testAttribute(Qt::WA_WState_Created));
00814 //    qDebug() << "repaint" << this << rgn;
00815     if (!QWidgetBackingStore::paintOnScreen(this)) {
00816         if (QWidgetBackingStore *bs = d->maybeBackingStore()) {
00817             QRegion wrgn(rgn);
00818             d->subtractOpaqueSiblings(wrgn, QPoint());
00819             d->subtractOpaqueChildren(wrgn, rect(), QPoint());
00820             bs->dirtyRegion(wrgn, this);
00821             bs->cleanRegion(wrgn, this);
00822         }
00823     }
00824 #ifndef Q_WS_QWS
00825 // QWS doesn't support paint-on-screen
00826     else {
00827         d->cleanWidget_sys(rgn);
00828         //     qDebug() << "QWidget::repaint paintOnScreen" << this << "region" << rgn;
00829       qt_flushPaint(this, rgn);
00830 
00831         QPaintEngine *engine = paintEngine();
00832 
00833         QRegion systemClipRgn(rgn);
00834 
00835         if (engine) {
00836             if (!data->wrect.topLeft().isNull()) {
00837                 QPainter::setRedirected(this, this, data->wrect.topLeft());
00838                 systemClipRgn.translate(-data->wrect.topLeft());
00839             }
00840             engine->setSystemClip(systemClipRgn);
00841             engine->setSystemRect(data->crect);
00842         }
00843 
00844         d->drawWidget(this, rgn, QPoint(), QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawPaintOnScreen);
00845 
00846 #ifdef Q_WS_WIN
00847         if (engine && engine->type() == QPaintEngine::Raster) {
00848             bool tmp_dc = !d->hd;
00849             if (tmp_dc)
00850                 d->hd = GetDC(winId());
00851             static_cast<QRasterPaintEngine *>(engine)->flush(this, QPoint(0, 0));
00852             if (tmp_dc) {
00853                 ReleaseDC(winId(), (HDC)d->hd);
00854                 d->hd = 0;
00855             }
00856         }
00857 #endif
00858         if (engine) {
00859             if (!data->wrect.topLeft().isNull())
00860                 QPainter::restoreRedirected(this);
00861             engine->setSystemClip(QRegion());
00862             engine->setSystemRect(QRect());
00863         }
00864 
00865         if(!testAttribute(Qt::WA_PaintOutsidePaintEvent) && paintingActive())
00866             qWarning("QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent");
00867     }
00868 #endif //Q_WS_QWS
00869 }
00870 
00871 void QWidget::update()
00872 {
00873     update(rect());
00874 }
00875 
00876 void QWidget::update(const QRect &r)
00877 {
00878     update(QRegion(r));
00879 }
00880 
00881 void QWidget::update(const QRegion& rgn)
00882 {
00883     if(!isVisible() || !updatesEnabled() || rgn.isEmpty())
00884         return;
00885 
00886     Q_D(QWidget);
00887     if (testAttribute(Qt::WA_WState_InPaintEvent)) {
00888         QApplication::postEvent(this, new QUpdateLaterEvent(rgn));
00889     } else {
00890         if (QWidgetBackingStore *bs = d->maybeBackingStore()) {
00891             QRegion wrgn(rgn);
00892             d->subtractOpaqueSiblings(wrgn, QPoint());
00893             d->subtractOpaqueChildren(wrgn, rect(), QPoint());
00894             bs->dirtyRegion(wrgn, this);
00895         }
00896     }
00897 }
00898 

Generated on Thu Mar 15 11:55:19 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1