void tst_QRegion::clipRectangles() { QRegion region(30, 30, 30, 30); int num = 0; qt_getClipRects(region, num); QCOMPARE(num, 1); region += QRegion(10, 10, 10, 10); XRectangle *rects2 = static_cast<XRectangle *>(qt_getClipRects(region, num)); QCOMPARE(num, 2); // Here's the important part (Y-sorted): QCOMPARE(int(rects2[0].y), 10); QCOMPARE(int(rects2[1].y), 30); }
void QX11WindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &offset) { if (d_ptr->device.isNull()) return; QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft(); QRegion wrgn(rgn); QRect br = rgn.boundingRect(); if (!wOffset.isNull()) wrgn.translate(-wOffset); QRect wbr = wrgn.boundingRect(); int num; XRectangle *rects = (XRectangle *)qt_getClipRects(wrgn, num); if (num <= 0) return; // qDebug() << "XSetClipRectangles"; // for (int i = 0; i < num; ++i) // qDebug() << ' ' << i << rects[i].x << rects[i].x << rects[i].y << rects[i].width << rects[i].height; if (num != 1) XSetClipRectangles(X11->display, gc, 0, 0, rects, num, YXBanded); XCopyArea(X11->display, d_ptr->device.handle(), widget->handle(), gc, br.x() + offset.x(), br.y() + offset.y(), br.width(), br.height(), wbr.x(), wbr.y()); if (num != 1) XSetClipMask(X11->display, gc, XNone); }
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); } }
void QX11WindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &offset) { if (d_ptr->device.isNull()) return; #ifndef Q_FLATTEN_EXPOSE extern void *qt_getClipRects(const QRegion &r, int &num); // in qpaintengine_x11.cpp extern QWidgetData* qt_widget_data(QWidget *); QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft(); GC gc = XCreateGC(X11->display, d_ptr->device.handle(), 0, 0); QRegion wrgn(rgn); QRect br = rgn.boundingRect(); if (!wOffset.isNull()) wrgn.translate(-wOffset); QRect wbr = wrgn.boundingRect(); // #### why dirty widget here? should be up to date already // if (br.right() + offset.x() >= d_ptr->device.size().width() || br.bottom() + offset.y() >= d_ptr->device.size().height()) { // // QRegion dirty = rgn - QRect(-offset, d_ptr->device.size()); // // qDebug() << dirty; // widget->d_func()->dirtyWidget_sys(rgn - QRect(-offset, d_ptr->device.size())); // } int num; XRectangle *rects = (XRectangle *)qt_getClipRects(wrgn, num); // qDebug() << "XSetClipRectangles"; // for (int i = 0; i < num; ++i) // qDebug() << " " << i << rects[i].x << rects[i].x << rects[i].y << rects[i].width << rects[i].height; XSetClipRectangles(X11->display, gc, 0, 0, rects, num, YXBanded); #else Q_UNUSED(rgn); XGCValues values; values.subwindow_mode = IncludeInferiors; GC gc = XCreateGC(X11->display, d_ptr->device.handle(), GCSubwindowMode, &values); #endif XSetGraphicsExposures(X11->display, gc, False); // XFillRectangle(X11->display, widget->handle(), gc, 0, 0, widget->width(), widget->height()); #ifndef Q_FLATTEN_EXPOSE XCopyArea(X11->display, d_ptr->device.handle(), widget->handle(), gc, br.x() + offset.x(), br.y() + offset.y(), br.width(), br.height(), wbr.x(), wbr.y()); #else Q_ASSERT(widget->isWindow()); XCopyArea(X11->display, d_ptr->device.handle(), widget->handle(), gc, offset.x(), offset.y(), widget->width(), widget->height(), 0, 0); #endif XFreeGC(X11->display, gc); }
void QX11GLWindowSurface::flush(QWidget *widget, const QRegion &widgetRegion, const QPoint &offset) { // We don't need to know the widget which initiated the flush. Instead we just use the offset // to translate the widgetRegion: Q_UNUSED(widget); if (m_backBuffer.isNull()) { qDebug("QX11GLWindowSurface::flush() - backBuffer is null, not flushing anything"); return; } Q_ASSERT(window()->size() != m_backBuffer.size()); // Wait for all GL rendering to the back buffer pixmap to complete before trying to // copy it to the window. We do this by making sure the pixmap's context is current // and then call eglWaitClient. The EGL 1.4 spec says eglWaitClient doesn't have to // block, just that "All rendering calls...are guaranteed to be executed before native // rendering calls". This makes it potentially less expensive than glFinish. QGLContext* ctx = static_cast<QX11GLPixmapData*>(m_backBuffer.data_ptr().data())->context(); if (QGLContext::currentContext() != ctx && ctx && ctx->isValid()) ctx->makeCurrent(); eglWaitClient(); if (m_windowGC == 0) { XGCValues attribs; attribs.graphics_exposures = False; m_windowGC = XCreateGC(X11->display, m_window->handle(), GCGraphicsExposures, &attribs); } int rectCount; XRectangle *rects = (XRectangle *)qt_getClipRects(widgetRegion, rectCount); if (rectCount <= 0) return; XSetClipRectangles(X11->display, m_windowGC, 0, 0, rects, rectCount, YXBanded); QRect dirtyRect = widgetRegion.boundingRect().translated(-offset); XCopyArea(X11->display, m_backBuffer.handle(), m_window->handle(), m_windowGC, dirtyRect.x(), dirtyRect.y(), dirtyRect.width(), dirtyRect.height(), dirtyRect.x(), dirtyRect.y()); // Make sure the blit of the update from the back buffer to the window completes // before allowing rendering to start again to the back buffer. Otherwise the GPU // might start rendering to the back buffer again while the blit takes place. eglWaitNative(EGL_CORE_NATIVE_ENGINE); }
void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &offset) { Q_D(QRasterWindowSurface); // Not ready for painting yet, bail out. This can happen in // QWidget::create_sys() if (!d->image || rgn.rectCount() == 0) return; #ifdef Q_WS_WIN QRect br = rgn.boundingRect(); if (!qt_widget_private(window())->isOpaque && window()->testAttribute(Qt::WA_TranslucentBackground) && (qt_widget_private(window())->data.window_flags & Qt::FramelessWindowHint)) { QRect r = window()->frameGeometry(); QPoint frameOffset = qt_widget_private(window())->frameStrut().topLeft(); QRect dirtyRect = br.translated(offset + frameOffset); SIZE size = {r.width(), r.height()}; POINT ptDst = {r.x(), r.y()}; POINT ptSrc = {0, 0}; BLENDFUNCTION blend = {AC_SRC_OVER, 0, (BYTE)(255.0 * window()->windowOpacity()), Q_AC_SRC_ALPHA}; RECT dirty = {dirtyRect.x(), dirtyRect.y(), dirtyRect.x() + dirtyRect.width(), dirtyRect.y() + dirtyRect.height()}; Q_UPDATELAYEREDWINDOWINFO info = {sizeof(info), NULL, &ptDst, &size, d->image->hdc, &ptSrc, 0, &blend, Q_ULW_ALPHA, &dirty}; ptrUpdateLayeredWindowIndirect(window()->internalWinId(), &info); } else { QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft(); HDC widget_dc = widget->getDC(); QRect wbr = br.translated(-wOffset); BitBlt(widget_dc, wbr.x(), wbr.y(), wbr.width(), wbr.height(), d->image->hdc, br.x() + offset.x(), br.y() + offset.y(), SRCCOPY); widget->releaseDC(widget_dc); } #ifndef QT_NO_DEBUG static bool flush = !qgetenv("QT_FLUSH_WINDOWSURFACE").isEmpty(); if (flush) { SelectObject(qt_win_display_dc(), GetStockObject(BLACK_BRUSH)); Rectangle(qt_win_display_dc(), 0, 0, d->image->width() + 2, d->image->height() + 2); BitBlt(qt_win_display_dc(), 1, 1, d->image->width(), d->image->height(), d->image->hdc, 0, 0, SRCCOPY); } #endif #endif #ifdef Q_WS_X11 extern void *qt_getClipRects(const QRegion &r, int &num); // in qpaintengine_x11.cpp extern QWidgetData* qt_widget_data(QWidget *); QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft(); if (widget->window() != window()) { XFreeGC(X11->display, d_ptr->gc); d_ptr->gc = XCreateGC(X11->display, widget->handle(), 0, 0); } QRegion wrgn(rgn); if (!wOffset.isNull()) wrgn.translate(-wOffset); if (wrgn.rectCount() != 1) { int num; XRectangle *rects = (XRectangle *)qt_getClipRects(wrgn, num); XSetClipRectangles(X11->display, d_ptr->gc, 0, 0, rects, num, YXBanded); } QPoint widgetOffset = offset + wOffset; QRect clipRect = widget->rect().translated(widgetOffset).intersected(d_ptr->image->image.rect()); QRect br = rgn.boundingRect().translated(offset).intersected(clipRect); QPoint wpos = br.topLeft() - widgetOffset; #ifndef QT_NO_MITSHM if (d_ptr->image->xshmpm) { XCopyArea(X11->display, d_ptr->image->xshmpm, widget->handle(), d_ptr->gc, br.x(), br.y(), br.width(), br.height(), wpos.x(), wpos.y()); d_ptr->needsSync = true; } else if (d_ptr->image->xshmimg) { XShmPutImage(X11->display, widget->handle(), d_ptr->gc, d_ptr->image->xshmimg, br.x(), br.y(), wpos.x(), wpos.y(), br.width(), br.height(), False); d_ptr->needsSync = true; } else #endif { int depth = widget->x11Info().depth(); const QImage &src = d->image->image; if (src.format() != QImage::Format_RGB32 || depth < 24 || X11->bppForDepth.value(depth) != 32) { Q_ASSERT(src.depth() >= 16); const QImage sub_src(src.scanLine(br.y()) + br.x() * (uint(src.depth()) / 8), br.width(), br.height(), src.bytesPerLine(), src.format()); QX11PixmapData *data = new QX11PixmapData(QPixmapData::PixmapType); data->xinfo = widget->x11Info(); data->fromImage(sub_src, Qt::NoOpaqueDetection); QPixmap pm = QPixmap(data); XCopyArea(X11->display, pm.handle(), widget->handle(), d_ptr->gc, 0 , 0 , br.width(), br.height(), wpos.x(), wpos.y()); } else { // qpaintengine_x11.cpp extern void qt_x11_drawImage(const QRect &rect, const QPoint &pos, const QImage &image, Drawable hd, GC gc, Display *dpy, Visual *visual, int depth); qt_x11_drawImage(br, wpos, src, widget->handle(), d_ptr->gc, X11->display, (Visual *)widget->x11Info().visual(), depth); } } if (wrgn.rectCount() != 1) XSetClipMask(X11->display, d_ptr->gc, XNone); #endif // FALCON #ifdef Q_WS_MAC Q_UNUSED(offset); // This is mainly done for native components like native "open file" dialog. if (widget->testAttribute(Qt::WA_DontShowOnScreen)) { return; } #ifdef QT_MAC_USE_COCOA this->needsFlush = true; this->regionToFlush += rgn; // The actual flushing will be processed in [view drawRect:rect] qt_mac_setNeedsDisplay(widget); #else // Get a context for the widget. CGContextRef context; CGrafPtr port = GetWindowPort(qt_mac_window_for(widget)); QDBeginCGContext(port, &context); CGContextRetain(context); CGContextSaveGState(context); // Flip context. CGContextTranslateCTM(context, 0, widget->height()); CGContextScaleCTM(context, 1, -1); // Clip to region. const QVector<QRect> &rects = rgn.rects(); for (int i = 0; i < rects.size(); ++i) { const QRect &rect = rects.at(i); CGContextAddRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height())); } CGContextClip(context); QRect r = rgn.boundingRect().intersected(d->image->image.rect()); const CGRect area = CGRectMake(r.x(), r.y(), r.width(), r.height()); CGImageRef image = CGBitmapContextCreateImage(d->image->cg); CGImageRef subImage = CGImageCreateWithImageInRect(image, area); qt_mac_drawCGImage(context, &area, subImage); CGImageRelease(subImage); CGImageRelease(image); QDEndCGContext(port, &context); // Restore context. CGContextRestoreGState(context); CGContextRelease(context); #endif // QT_MAC_USE_COCOA #endif // Q_WS_MAC }
void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &offset) { Q_D(QRasterWindowSurface); // Not ready for painting yet, bail out. This can happen in // QWidget::create_sys() if (!d->image) return; #ifdef Q_WS_WIN QRect br = rgn.boundingRect(); #ifndef Q_OS_WINCE if (!qt_widget_private(window())->isOpaque && d->canUseLayeredWindow) { QRect r = window()->frameGeometry(); QPoint frameOffset = qt_widget_private(window())->frameStrut().topLeft(); QRect dirtyRect = br.translated(offset + frameOffset); SIZE size = {r.width(), r.height()}; POINT ptDst = {r.x(), r.y()}; POINT ptSrc = {0, 0}; Q_BLENDFUNCTION blend = {AC_SRC_OVER, 0, (int)(255.0 * window()->windowOpacity()), Q_AC_SRC_ALPHA}; RECT dirty = {dirtyRect.x(), dirtyRect.y(), dirtyRect.x() + dirtyRect.width(), dirtyRect.y() + dirtyRect.height()}; Q_UPDATELAYEREDWINDOWINFO info = {sizeof(info), NULL, &ptDst, &size, d->image->hdc, &ptSrc, 0, &blend, Q_ULW_ALPHA, &dirty}; (*ptrUpdateLayeredWindowIndirect)(window()->internalWinId(), &info); } else #endif { QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft(); HDC widget_dc = widget->getDC(); QRect wbr = br.translated(-wOffset); BitBlt(widget_dc, wbr.x(), wbr.y(), wbr.width(), wbr.height(), d->image->hdc, br.x() + offset.x(), br.y() + offset.y(), SRCCOPY); widget->releaseDC(widget_dc); } #ifndef QT_NO_DEBUG static bool flush = !qgetenv("QT_FLUSH_WINDOWSURFACE").isEmpty(); if (flush) { SelectObject(qt_win_display_dc(), GetStockObject(BLACK_BRUSH)); Rectangle(qt_win_display_dc(), 0, 0, d->image->width() + 2, d->image->height() + 2); BitBlt(qt_win_display_dc(), 1, 1, d->image->width(), d->image->height(), d->image->hdc, 0, 0, SRCCOPY); } #endif #endif #ifdef Q_WS_X11 extern void *qt_getClipRects(const QRegion &r, int &num); // in qpaintengine_x11.cpp extern QWidgetData* qt_widget_data(QWidget *); QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft(); if (widget->window() != window()) { XFreeGC(X11->display, d_ptr->gc); d_ptr->gc = XCreateGC(X11->display, widget->handle(), 0, 0); } QRegion wrgn(rgn); if (!wOffset.isNull()) wrgn.translate(-wOffset); QRect wbr = wrgn.boundingRect(); int num; XRectangle *rects = (XRectangle *)qt_getClipRects(wrgn, num); XSetClipRectangles(X11->display, d_ptr->gc, 0, 0, rects, num, YXBanded); QRect br = rgn.boundingRect().translated(offset); #ifndef QT_NO_MITSHM if (d_ptr->image->xshmpm) { XCopyArea(X11->display, d_ptr->image->xshmpm, widget->handle(), d_ptr->gc, br.x(), br.y(), br.width(), br.height(), wbr.x(), wbr.y()); XSync(X11->display, False); } else #endif { const QImage &src = d->image->image; br = br.intersected(src.rect()); if (src.format() != QImage::Format_RGB32) { QX11PixmapData *data = new QX11PixmapData(QPixmapData::PixmapType); data->xinfo = widget->x11Info(); data->fromImage(src, Qt::AutoColor); QPixmap pm = QPixmap(data); XCopyArea(X11->display, pm.handle(), widget->handle(), d_ptr->gc, br.x() , br.y() , br.width(), br.height(), wbr.x(), wbr.y()); } else { // qpaintengine_x11.cpp extern void qt_x11_drawImage(const QRect &rect, const QPoint &pos, const QImage &image, Drawable hd, GC gc, Display *dpy, Visual *visual, int depth); qt_x11_drawImage(br, wbr.topLeft(), src, widget->handle(), d_ptr->gc, X11->display, (Visual *)widget->x11Info().visual(), widget->x11Info().depth()); } } #endif // FALCON #ifdef Q_WS_MAC // qDebug() << "Flushing" << widget << rgn << offset; // d->image->image.save("flush.png"); // Get a context for the widget. #ifndef QT_MAC_USE_COCOA CGContextRef context; CGrafPtr port = GetWindowPort(qt_mac_window_for(widget)); QDBeginCGContext(port, &context); #else extern CGContextRef qt_mac_graphicsContextFor(QWidget *); CGContextRef context = qt_mac_graphicsContextFor(widget); #endif CGContextSaveGState(context); // Flip context. CGContextTranslateCTM(context, 0, widget->height()); CGContextScaleCTM(context, 1, -1); // Clip to region. const QVector<QRect> &rects = rgn.rects(); for (int i = 0; i < rects.size(); ++i) { const QRect &rect = rects.at(i); CGContextAddRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height())); } CGContextClip(context); QRect r = rgn.boundingRect(); const CGRect area = CGRectMake(r.x(), r.y(), r.width(), r.height()); CGImageRef image = CGBitmapContextCreateImage(d->image->cg); CGImageRef subImage = CGImageCreateWithImageInRect(image, area); qt_mac_drawCGImage(context, &area, subImage); CGImageRelease(subImage); CGImageRelease(image); // CGSize size = { d->image->image.width(), d->image->image.height() }; // CGLayerRef layer = CGLayerCreateWithContext(d->image->cg, size, 0); // CGPoint pt = { 0, 0 }; // CGContextDrawLayerAtPoint(context, pt, layer); // CGLayerRelease(layer); // Restore context. CGContextRestoreGState(context); #ifndef QT_MAC_USE_COCOA QDEndCGContext(port, &context); #else CGContextFlush(context); #endif #endif }