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); } }
QMeeGoLivePixmapData::QMeeGoLivePixmapData(int w, int h, QImage::Format format) : QGLPixmapData(QPixmapData::PixmapType) { QImage image(w, h, format); QX11PixmapData *pmd = new QX11PixmapData(QPixmapData::PixmapType); pmd->fromImage(image, Qt::NoOpaqueDetection); backingX11Pixmap = new QPixmap(pmd); initializeThroughEGLImage(); }
QPixmap QX11GLWindowSurface::grabWidget(const QWidget *widget, const QRect& rect) const { if (!widget || m_backBuffer.isNull()) return QPixmap(); QRect srcRect; // make sure the rect is inside the widget & clip to widget's rect if (!rect.isEmpty()) srcRect = rect & widget->rect(); else srcRect = widget->rect(); if (srcRect.isEmpty()) return QPixmap(); // If it's a child widget we have to translate the coordinates if (widget != window()) srcRect.translate(widget->mapTo(window(), QPoint(0, 0))); QPixmap::x11SetDefaultScreen(widget->x11Info().screen()); QX11PixmapData *pmd = new QX11PixmapData(QPixmapData::PixmapType); pmd->resize(srcRect.width(), srcRect.height()); QPixmap px(pmd); GC tmpGc = XCreateGC(X11->display, m_backBuffer.handle(), 0, 0); // Make sure all GL rendering is complete before copying the window QGLContext* ctx = static_cast<QX11GLPixmapData*>(m_backBuffer.pixmapData())->context(); if (QGLContext::currentContext() != ctx && ctx && ctx->isValid()) ctx->makeCurrent(); eglWaitClient(); // Copy srcRect from the backing store to the new pixmap XSetGraphicsExposures(X11->display, tmpGc, False); XCopyArea(X11->display, m_backBuffer.handle(), px.handle(), tmpGc, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(), 0, 0); XFreeGC(X11->display, tmpGc); // Wait until the copy has finised before allowing more rendering into the back buffer eglWaitNative(EGL_CORE_NATIVE_ENGINE); return px; }
EGLSurface QMeeGoLivePixmapData::getSurfaceForBackingPixmap() { initializeThroughEGLImage(); // This code is a crative remix of the stuff that can be found in the // Qt's TFP implementation in /src/opengl/qgl_x11egl.cpp ::bindiTextureFromNativePixmap QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(backingX11Pixmap->data_ptr().data()); Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class); bool hasAlpha = pixmapData->hasAlphaChannel(); if (pixmapData->gl_surface && hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) return pixmapData->gl_surface; // Check to see if the surface is still valid if (pixmapData->gl_surface && hasAlpha != ((pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha) > 0)) { // Surface is invalid! destroySurfaceForPixmapData(pixmapData); } if (pixmapData->gl_surface == 0) { EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, hasAlpha ? QEgl::Translucent : QEgl::NoOptions); pixmapData->gl_surface = (void*)QEgl::createSurface(backingX11Pixmap, config); if (hasAlpha) pixmapData->flags |= QX11PixmapData::GlSurfaceCreatedWithAlpha; else pixmapData->flags &= ~QX11PixmapData::GlSurfaceCreatedWithAlpha; if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE) return NULL; } return pixmapData->gl_surface; }
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 }
QX11GLSharedContexts() : rgbContext(0) , argbContext(0) , sharedQGLContext(0) , sharePixmap(0) { EGLint rgbConfigId; EGLint argbConfigId; do { EGLConfig rgbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, QEgl::Renderable); EGLConfig argbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, QEgl::Renderable | QEgl::Translucent); eglGetConfigAttrib(QEgl::display(), rgbConfig, EGL_CONFIG_ID, &rgbConfigId); eglGetConfigAttrib(QEgl::display(), argbConfig, EGL_CONFIG_ID, &argbConfigId); rgbContext = new QEglContext; rgbContext->setConfig(rgbConfig); rgbContext->createContext(); if (!rgbContext->isValid()) break; // If the RGB & ARGB configs are the same, use the same egl context for both: if (rgbConfig == argbConfig) argbContext = rgbContext; // Otherwise, create a separate context to be used for ARGB pixmaps: if (!argbContext) { argbContext = new QEglContext; argbContext->setConfig(argbConfig); bool success = argbContext->createContext(rgbContext); if (!success) { qWarning("QX11GLPixmapData - RGB & ARGB contexts aren't shared"); success = argbContext->createContext(); if (!success) argbContext = rgbContext; // Might work, worth a shot at least. } } if (!argbContext->isValid()) break; // Create the pixmap which will be used to create the egl surface for the share QGLContext QX11PixmapData *rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); rgbPixmapData->resize(8, 8); rgbPixmapData->fill(Qt::red); sharePixmap = new QPixmap(rgbPixmapData); EGLSurface sharePixmapSurface = QEgl::createSurface(sharePixmap, rgbConfig); rgbPixmapData->gl_surface = (void*)sharePixmapSurface; // Create the actual QGLContext which will be used for sharing sharedQGLContext = new QGLContext(QX11GLPixmapData::glFormat()); sharedQGLContext->d_func()->eglContext = rgbContext; sharedQGLContext->d_func()->eglSurface = sharePixmapSurface; sharedQGLContext->d_func()->valid = true; qt_glformat_from_eglconfig(sharedQGLContext->d_func()->glFormat, rgbConfig); valid = rgbContext->makeCurrent(sharePixmapSurface); // If the ARGB & RGB configs are different, check ARGB works too: if (argbConfig != rgbConfig) { QX11PixmapData *argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); argbPixmapData->resize(8, 8); argbPixmapData->fill(Qt::transparent); // Force ARGB QPixmap argbPixmap(argbPixmapData); // destroys pixmap data when goes out of scope EGLSurface argbPixmapSurface = QEgl::createSurface(&argbPixmap, argbConfig); valid = argbContext->makeCurrent(argbPixmapSurface); argbContext->doneCurrent(); eglDestroySurface(QEgl::display(), argbPixmapSurface); argbPixmapData->gl_surface = 0; } if (!valid) { qWarning() << "Unable to make pixmap surface current:" << QEgl::errorString(); break; } // The pixmap surface destruction hooks are installed by QGLTextureCache, so we // must make sure this is instanciated: QGLTextureCache::instance(); } while(0); if (!valid) cleanup(); else qDebug("Using QX11GLPixmapData with EGL config %d for ARGB and config %d for RGB", argbConfigId, rgbConfigId); }
QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, const qint64 key, QGLContext::BindOptions options) { Q_Q(QGLContext); // The EGL texture_from_pixmap has no facility to invert the y coordinate if (!(options & QGLContext::CanFlipNativePixmapBindOption)) return 0; static bool checkedForTFP = false; static bool haveTFP = false; static bool checkedForEglImageTFP = false; static bool haveEglImageTFP = false; if (!checkedForEglImageTFP) { checkedForEglImageTFP = true; // We need to be able to create an EGLImage from a native pixmap, which was split // into a separate EGL extension, EGL_KHR_image_pixmap. It is possible to have // eglCreateImageKHR & eglDestroyImageKHR without support for pixmaps, so we must // check we have the EGLImage from pixmap functionality. if (QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_pixmap")) { // Being able to create an EGLImage from a native pixmap is also pretty useless // without the ability to bind that EGLImage as a texture, which is provided by // the GL_OES_EGL_image extension, which we try to resolve here: haveEglImageTFP = qt_resolve_eglimage_gl_extensions(q); if (haveEglImageTFP) qDebug("Found EGL_KHR_image_pixmap & GL_OES_EGL_image extensions (preferred method)!"); } } if (!checkedForTFP) { // Check for texture_from_pixmap egl extension checkedForTFP = true; if (QEgl::hasExtension("EGL_NOKIA_texture_from_pixmap") || QEgl::hasExtension("EGL_EXT_texture_from_pixmap")) { qDebug("Found texture_from_pixmap EGL extension!"); haveTFP = true; } } if (!haveTFP && !haveEglImageTFP) return 0; QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pixmap->data_ptr().data()); Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class); bool hasAlpha = pixmapData->hasAlphaChannel(); bool pixmapHasValidSurface = false; bool textureIsBound = false; GLuint textureId; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId); if (haveTFP && pixmapData->gl_surface && hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) { pixmapHasValidSurface = true; } // If we already have a valid EGL surface for the pixmap, we should use it if (pixmapHasValidSurface) { EGLBoolean success; success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER); if (success == EGL_FALSE) { qWarning() << "eglBindTexImage() failed:" << QEgl::errorString(); eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface); pixmapData->gl_surface = (void*)EGL_NO_SURFACE; } else textureIsBound = true; } // If the pixmap doesn't already have a valid surface, try binding it via EGLImage // first, as going through EGLImage should be faster and better supported: if (!textureIsBound && haveEglImageTFP) { EGLImageKHR eglImage; EGLint attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; eglImage = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer)QEgl::nativePixmap(pixmap), attribs); QGLContext* ctx = q; glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage); GLint err = glGetError(); if (err == GL_NO_ERROR) textureIsBound = true; // Once the egl image is bound, the texture becomes a new sibling image and we can safely // destroy the EGLImage we created for the pixmap: if (eglImage != EGL_NO_IMAGE_KHR) QEgl::eglDestroyImageKHR(QEgl::display(), eglImage); } if (!textureIsBound && haveTFP) { // Check to see if the surface is still valid if (pixmapData->gl_surface && hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) { // Surface is invalid! destroyGlSurfaceForPixmap(pixmapData); } if (pixmapData->gl_surface == 0) { EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, hasAlpha ? QEgl::Translucent : QEgl::NoOptions); pixmapData->gl_surface = (void*)QEgl::createSurface(pixmap, config); if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE) return false; } EGLBoolean success; success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER); if (success == EGL_FALSE) { qWarning() << "eglBindTexImage() failed:" << QEgl::errorString(); eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface); pixmapData->gl_surface = (void*)EGL_NO_SURFACE; haveTFP = false; // If TFP isn't working, disable it's use } else textureIsBound = true; } QGLTexture *texture = 0; if (textureIsBound) { texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options); pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture; // We assume the cost of bound pixmaps is zero QGLTextureCache::instance()->insert(q, key, texture, 0); glBindTexture(GL_TEXTURE_2D, textureId); } else glDeleteTextures(1, &textureId); return texture; }
bool QX11GLPixmapData::hasX11GLPixmaps() { static bool checkedForX11Pixmaps = false; static bool haveX11Pixmaps = false; if (checkedForX11Pixmaps) return haveX11Pixmaps; checkedForX11Pixmaps = true; QX11PixmapData *argbPixmapData = 0; QX11PixmapData *rgbPixmapData = 0; do { if (qgetenv("QT_USE_X11GL_PIXMAPS").isEmpty()) break; // Check we actually have EGL configs which support pixmaps EGLConfig argbConfig = qt_chooseEGLConfigForPixmap(true, false); EGLConfig rgbConfig = qt_chooseEGLConfigForPixmap(false, false); if (argbConfig == 0 || rgbConfig == 0) break; // Create the shared contexts: eglBindAPI(EGL_OPENGL_ES_API); EGLint contextAttribs[] = { #if defined(QT_OPENGL_ES_2) EGL_CONTEXT_CLIENT_VERSION, 2, #endif EGL_NONE }; qPixmapARGBSharedEglContext = eglCreateContext(QEglContext::defaultDisplay(0), argbConfig, 0, contextAttribs); if (argbConfig == rgbConfig) { // If the configs are the same, we can re-use the same context. qPixmapRGBSharedEglContext = qPixmapARGBSharedEglContext; } else { qPixmapRGBSharedEglContext = eglCreateContext(QEglContext::defaultDisplay(0), rgbConfig, 0, contextAttribs); } argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); argbPixmapData->resize(100, 100); argbPixmapData->fill(Qt::transparent); // Force ARGB if (!qt_createEGLSurfaceForPixmap(argbPixmapData, false)) break; haveX11Pixmaps = eglMakeCurrent(QEglContext::defaultDisplay(0), (EGLSurface)argbPixmapData->gl_surface, (EGLSurface)argbPixmapData->gl_surface, qPixmapARGBSharedEglContext); if (!haveX11Pixmaps) { EGLint err = eglGetError(); qWarning() << "Unable to make pixmap config current:" << err << QEglContext::errorString(err); break; } // If the ARGB & RGB configs are the same, we don't need to check RGB too if (haveX11Pixmaps && (argbConfig != rgbConfig)) { rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); rgbPixmapData->resize(100, 100); rgbPixmapData->fill(Qt::red); // Try to actually create an EGL pixmap surface if (!qt_createEGLSurfaceForPixmap(rgbPixmapData, false)) break; haveX11Pixmaps = eglMakeCurrent(QEglContext::defaultDisplay(0), (EGLSurface)rgbPixmapData->gl_surface, (EGLSurface)rgbPixmapData->gl_surface, qPixmapRGBSharedEglContext); if (!haveX11Pixmaps) { EGLint err = eglGetError(); qWarning() << "Unable to make pixmap config current:" << err << QEglContext::errorString(err); break; } } } while (0); if (qPixmapARGBSharedEglContext || qPixmapRGBSharedEglContext) { eglMakeCurrent(QEglContext::defaultDisplay(0), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } if (argbPixmapData) { if (argbPixmapData->gl_surface) QGLContextPrivate::destroyGlSurfaceForPixmap(argbPixmapData); delete argbPixmapData; argbPixmapData = 0; } if (rgbPixmapData) { if (rgbPixmapData->gl_surface) QGLContextPrivate::destroyGlSurfaceForPixmap(rgbPixmapData); delete rgbPixmapData; rgbPixmapData = 0; } if (!haveX11Pixmaps) { // Clean up the context(s) if we can't use X11GL pixmaps if (qPixmapARGBSharedEglContext != EGL_NO_CONTEXT) eglDestroyContext(QEglContext::defaultDisplay(0), qPixmapARGBSharedEglContext); if (qPixmapRGBSharedEglContext != qPixmapARGBSharedEglContext && qPixmapRGBSharedEglContext != EGL_NO_CONTEXT) { eglDestroyContext(QEglContext::defaultDisplay(0), qPixmapRGBSharedEglContext); } qPixmapRGBSharedEglContext = EGL_NO_CONTEXT; qPixmapARGBSharedEglContext = EGL_NO_CONTEXT; } if (haveX11Pixmaps) qDebug("QX11GLPixmapData is supported"); else qDebug("QX11GLPixmapData is *NOT* being used"); return haveX11Pixmaps; }
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 }