void QRasterWindowSurface::prepareBuffer(QImage::Format format, QWidget *widget) { Q_D(QRasterWindowSurface); int width = window()->width(); int height = window()->height(); if (d->image) { width = qMax(d->image->width(), width); height = qMax(d->image->height(), height); } if (width == 0 || height == 0) { delete d->image; d->image = 0; return; } QNativeImage *oldImage = d->image; d->image = new QNativeImage(width, height, format, false, widget); if (oldImage && d->inSetGeometry && hasStaticContents()) { // Make sure we use the const version of bits() (no detach). const uchar *src = const_cast<const QImage &>(oldImage->image).bits(); uchar *dst = d->image->image.bits(); const int srcBytesPerLine = oldImage->image.bytesPerLine(); const int dstBytesPerLine = d->image->image.bytesPerLine(); const int bytesPerPixel = oldImage->image.depth() >> 3; QRegion staticRegion(staticContents()); // Make sure we're inside the boundaries of the old image. staticRegion &= QRect(0, 0, oldImage->image.width(), oldImage->image.height()); const QVector<QRect> &rects = staticRegion.rects(); const QRect *srcRect = rects.constData(); // Copy the static content of the old image into the new one. int numRectsLeft = rects.size(); do { const int bytesOffset = srcRect->x() * bytesPerPixel; const int dy = srcRect->y(); // Adjust src and dst to point to the right offset. const uchar *s = src + dy * srcBytesPerLine + bytesOffset; uchar *d = dst + dy * dstBytesPerLine + bytesOffset; const int numBytes = srcRect->width() * bytesPerPixel; int numScanLinesLeft = srcRect->height(); do { ::memcpy(d, s, numBytes); d += dstBytesPerLine; s += srcBytesPerLine; } while (--numScanLinesLeft); ++srcRect; } while (--numRectsLeft); } delete oldImage; }
void QX11WindowSurface::setGeometry(const QRect &rect) { QWindowSurface::setGeometry(rect); const QSize size = rect.size(); if (d_ptr->device.size() == size || size.width() <= 0 || size.height() <= 0) return; #ifndef QT_NO_XRENDER if (d_ptr->translucentBackground) { QX11PixmapData *data = new QX11PixmapData(QPixmapData::PixmapType); data->xinfo = d_ptr->widget->x11Info(); data->resize(size.width(), size.height()); d_ptr->device = QPixmap(data); } else #endif { QPixmap::x11SetDefaultScreen(d_ptr->widget->x11Info().screen()); QX11PixmapData *oldData = static_cast<QX11PixmapData *>(d_ptr->device.pixmapData()); if (oldData && !(oldData->flags & QX11PixmapData::Uninitialized) && hasStaticContents()) { // Copy the content of the old pixmap into the new one. QX11PixmapData *newData = new QX11PixmapData(QPixmapData::PixmapType); newData->resize(size.width(), size.height()); Q_ASSERT(oldData->d == newData->d); QRegion staticRegion(staticContents()); // Make sure we're inside the boundaries of the old pixmap. staticRegion &= QRect(0, 0, oldData->w, oldData->h); const QRect boundingRect(staticRegion.boundingRect()); const int dx = boundingRect.x(); const int dy = boundingRect.y(); int num; XRectangle *rects = (XRectangle *)qt_getClipRects(staticRegion, num); GC tmpGc = XCreateGC(X11->display, oldData->hd, 0, 0); XSetClipRectangles(X11->display, tmpGc, 0, 0, rects, num, YXBanded); XCopyArea(X11->display, oldData->hd, newData->hd, tmpGc, dx, dy, qMin(boundingRect.width(), size.width()), qMin(boundingRect.height(), size.height()), dx, dy); XFreeGC(X11->display, tmpGc); newData->flags &= ~QX11PixmapData::Uninitialized; d_ptr->device = QPixmap(newData); } else { d_ptr->device = QPixmap(size); } } if (gc) { XFreeGC(X11->display, gc); gc = 0; } if (!d_ptr->device.isNull()) { gc = XCreateGC(X11->display, d_ptr->device.handle(), 0, 0); XSetGraphicsExposures(X11->display, gc, False); } }
/*! Synchronizes the backing store, i.e. dirty areas are repainted and flushed. */ void QWidgetBackingStore::sync() { QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); if (discardSyncRequest(tlw, tlwExtra)) { // If the top-level is minimized, it's not visible on the screen so we can delay the // update until it's shown again. In order to do that we must keep the dirty states. // These will be cleared when we receive the first expose after showNormal(). // However, if the widget is not visible (isVisible() returns false), everything will // be invalidated once the widget is shown again, so clear all dirty states. if (!tlw->isVisible()) { dirty = QRegion(); for (int i = 0; i < dirtyWidgets.size(); ++i) resetWidget(dirtyWidgets.at(i)); dirtyWidgets.clear(); fullUpdatePending = false; } return; } const bool updatesDisabled = !tlw->updatesEnabled(); bool repaintAllWidgets = false; const bool inTopLevelResize = tlwExtra->inTopLevelResize; const QRect tlwRect(tlw->data->crect); const QRect surfaceGeometry(windowSurface->geometry()); if ((fullUpdatePending || inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) { if (hasStaticContents()) { // Repaint existing dirty area and newly visible area. const QRect clipRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); const QRegion staticRegion(staticContents(0, clipRect)); QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height()); newVisible -= staticRegion; dirty += newVisible; windowSurface->setStaticContents(staticRegion); } else { // Repaint everything. dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height()); for (int i = 0; i < dirtyWidgets.size(); ++i) resetWidget(dirtyWidgets.at(i)); dirtyWidgets.clear(); repaintAllWidgets = true; } } if (inTopLevelResize || surfaceGeometry != tlwRect) windowSurface->setGeometry(tlwRect); if (updatesDisabled) return; if (hasDirtyFromPreviousSync) dirty += dirtyFromPreviousSync; // Contains everything that needs repaint. QRegion toClean(dirty); // Loop through all update() widgets and remove them from the list before they are // painted (in case someone calls update() in paintEvent). If the widget is opaque // and does not have transparent overlapping siblings, append it to the // opaqueNonOverlappedWidgets list and paint it directly without composition. QVarLengthArray<QWidget *, 32> opaqueNonOverlappedWidgets; for (int i = 0; i < dirtyWidgets.size(); ++i) { QWidget *w = dirtyWidgets.at(i); QWidgetPrivate *wd = w->d_func(); if (wd->data.in_destructor) continue; // Clip with mask() and clipRect(). wd->dirty &= wd->clipRect(); wd->clipToEffectiveMask(wd->dirty); // Subtract opaque siblings and children. bool hasDirtySiblingsAbove = false; // We know for sure that the widget isn't overlapped if 'isMoved' is true. if (!wd->isMoved) wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove); // Scrolled and moved widgets must draw all children. if (!wd->isScrolled && !wd->isMoved) wd->subtractOpaqueChildren(wd->dirty, w->rect()); if (wd->dirty.isEmpty()) { resetWidget(w); continue; } const QRegion widgetDirty(w != tlw ? wd->dirty.translated(w->mapTo(tlw, QPoint())) : wd->dirty); toClean += widgetDirty; #ifndef QT_NO_GRAPHICSVIEW if (tlw->d_func()->extra->proxyWidget) { resetWidget(w); continue; } #endif if (!hasDirtySiblingsAbove && wd->isOpaque && !dirty.intersects(widgetDirty.boundingRect())) { opaqueNonOverlappedWidgets.append(w); } else { resetWidget(w); dirty += widgetDirty; } } dirtyWidgets.clear(); fullUpdatePending = false; if (toClean.isEmpty()) { // Nothing to repaint. However, we might have newly exposed areas on the // screen if this function was called from sync(QWidget *, QRegion)), so // we have to make sure those are flushed. flush(); return; } #ifndef QT_NO_GRAPHICSVIEW if (tlw->d_func()->extra->proxyWidget) { updateStaticContentsSize(); dirty = QRegion(); const QVector<QRect> rects(toClean.rects()); for (int i = 0; i < rects.size(); ++i) tlw->d_func()->extra->proxyWidget->update(rects.at(i)); return; } #endif #ifndef Q_BACKINGSTORE_SUBSURFACES BeginPaintInfo beginPaintInfo; beginPaint(toClean, tlw, windowSurface, &beginPaintInfo); if (beginPaintInfo.nothingToPaint) { for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) resetWidget(opaqueNonOverlappedWidgets[i]); dirty = QRegion(); return; } #endif // Must do this before sending any paint events because // the size may change in the paint event. updateStaticContentsSize(); const QRegion dirtyCopy(dirty); dirty = QRegion(); // Paint opaque non overlapped widgets. for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) { QWidget *w = opaqueNonOverlappedWidgets[i]; QWidgetPrivate *wd = w->d_func(); int flags = QWidgetPrivate::DrawRecursive; // Scrolled and moved widgets must draw all children. if (!wd->isScrolled && !wd->isMoved) flags |= QWidgetPrivate::DontDrawOpaqueChildren; if (w == tlw) flags |= QWidgetPrivate::DrawAsRoot; QRegion toBePainted(wd->dirty); resetWidget(w); #ifdef Q_BACKINGSTORE_SUBSURFACES QWindowSurface *subSurface = w->windowSurface(); BeginPaintInfo beginPaintInfo; QPoint off = w->mapTo(tlw, QPoint()); toBePainted.translate(off); beginPaint(toBePainted, w, subSurface, &beginPaintInfo, true); toBePainted.translate(-off); if (beginPaintInfo.nothingToPaint) continue; if (beginPaintInfo.windowSurfaceRecreated) { // Eep the window surface has changed. The old one may have been // deleted, in which case we will segfault on the call to // painterOffset() below. Use the new window surface instead. subSurface = w->windowSurface(); } QPoint offset(tlwOffset); if (subSurface == windowSurface) offset += w->mapTo(tlw, QPoint()); else offset = static_cast<QWSWindowSurface*>(subSurface)->painterOffset(); wd->drawWidget(subSurface->paintDevice(), toBePainted, offset, flags, 0, this); endPaint(toBePainted, subSurface, &beginPaintInfo); #else QPoint offset(tlwOffset); if (w != tlw) offset += w->mapTo(tlw, QPoint()); wd->drawWidget(windowSurface->paintDevice(), toBePainted, offset, flags, 0, this); #endif } // Paint the rest with composition. #ifndef Q_BACKINGSTORE_SUBSURFACES if (repaintAllWidgets || !dirtyCopy.isEmpty()) { const int flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive; tlw->d_func()->drawWidget(windowSurface->paintDevice(), dirtyCopy, tlwOffset, flags, 0, this); } endPaint(toClean, windowSurface, &beginPaintInfo); #else if (!repaintAllWidgets && dirtyCopy.isEmpty()) return; // Nothing more to paint. QList<QWindowSurface *> surfaceList(subSurfaces); surfaceList.prepend(windowSurface); const QRect dirtyBoundingRect(dirtyCopy.boundingRect()); // Loop through all window surfaces (incl. the top-level surface) and // repaint those intersecting with the bounding rect of the dirty region. for (int i = 0; i < surfaceList.size(); ++i) { QWindowSurface *subSurface = surfaceList.at(i); QWidget *w = subSurface->window(); QWidgetPrivate *wd = w->d_func(); const QRect clipRect = wd->clipRect().translated(w->mapTo(tlw, QPoint())); if (!qRectIntersects(dirtyBoundingRect, clipRect)) continue; toClean = dirtyCopy; BeginPaintInfo beginPaintInfo; beginPaint(toClean, w, subSurface, &beginPaintInfo); if (beginPaintInfo.nothingToPaint) continue; if (beginPaintInfo.windowSurfaceRecreated) { // Eep the window surface has changed. The old one may have been // deleted, in which case we will segfault on the call to // painterOffset() below. Use the new window surface instead. subSurface = w->windowSurface(); } int flags = QWidgetPrivate::DrawRecursive; if (w == tlw) flags |= QWidgetPrivate::DrawAsRoot; const QPoint painterOffset = static_cast<QWSWindowSurface*>(subSurface)->painterOffset(); wd->drawWidget(subSurface->paintDevice(), toClean, painterOffset, flags, 0, this); endPaint(toClean, subSurface, &beginPaintInfo); } #endif }