uint QGLContext::colorIndex(const QColor& c) const { Q_D(const QGLContext); int screen = ((XVisualInfo *)d->vi)->screen; QColormap colmap = QColormap::instance(screen); if (isValid()) { if (format().plane() && c == Qt::transparent) { return qt_transparent_pixel(((XVisualInfo *)d->vi)->visualid, ((XVisualInfo *)d->vi)->screen); } if (((XVisualInfo*)d->vi)->visualid == XVisualIDFromVisual((Visual *) QX11Info::appVisual(screen))) return colmap.pixel(c); // We're using QColor's cmap XVisualInfo *info = (XVisualInfo *) d->vi; CMapEntryHash *hash = cmap_handler()->cmap_hash; CMapEntryHash::ConstIterator it = hash->constFind(long(info->visualid) + (info->screen * 256)); QCMapEntry *x = 0; if (it != hash->constEnd()) x = it.value(); if (x && !x->alloc) { // It's a standard colormap int rf = (int)(((float)c.red() * (x->scmap.red_max+1))/256.0); int gf = (int)(((float)c.green() * (x->scmap.green_max+1))/256.0); int bf = (int)(((float)c.blue() * (x->scmap.blue_max+1))/256.0); uint p = x->scmap.base_pixel + (rf * x->scmap.red_mult) + (gf * x->scmap.green_mult) + (bf * x->scmap.blue_mult); return p; } else { QMap<int, QRgb> &cmap = (*cmap_handler()->qglcmap_hash)[(long)info->visualid]; // already in the map? QRgb target = c.rgb(); QMap<int, QRgb>::Iterator it = cmap.begin(); for (; it != cmap.end(); ++it) { if ((*it) == target) return it.key(); } // need to alloc color unsigned long plane_mask[2]; unsigned long color_map_entry; if (!XAllocColorCells (QX11Info::display(), x->cmap, true, plane_mask, 0, &color_map_entry, 1)) return colmap.pixel(c); XColor col; col.flags = DoRed | DoGreen | DoBlue; col.pixel = color_map_entry; col.red = (ushort)((qRed(c.rgb()) / 255.0) * 65535.0 + 0.5); col.green = (ushort)((qGreen(c.rgb()) / 255.0) * 65535.0 + 0.5); col.blue = (ushort)((qBlue(c.rgb()) / 255.0) * 65535.0 + 0.5); XStoreColor(QX11Info::display(), x->cmap, &col); cmap.insert(color_map_entry, target); return color_map_entry; } } return 0; }
// NOTE: The X11 version of createSurface will re-create the native drawable if it's visual doesn't // match the one for the passed in EGLConfig EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig config, const QEglProperties *unusedProperties) { Q_UNUSED(unusedProperties); int devType = device->devType(); if (devType == QInternal::Pbuffer) { // TODO return EGL_NO_SURFACE; } QX11PixmapData *x11PixmapData = 0; if (devType == QInternal::Pixmap) { QPixmapData *pmd = static_cast<QPixmap*>(device)->data_ptr().data(); if (pmd->classId() == QPixmapData::X11Class) x11PixmapData = static_cast<QX11PixmapData*>(pmd); else { // TODO: Replace the pixmap's data with a new QX11PixmapData qWarning("WARNING: Creating an EGL surface on a QPixmap is only supported for QX11PixmapData"); return EGL_NO_SURFACE; } } else if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) { qWarning("WARNING: Creating an EGLSurface for device type %d isn't supported", devType); return EGL_NO_SURFACE; } VisualID visualId = QEgl::getCompatibleVisualId(config); EGLint alphaSize; eglGetConfigAttrib(QEgl::display(), config, EGL_ALPHA_SIZE, &alphaSize); if (devType == QInternal::Widget) { QWidget *widget = static_cast<QWidget*>(device); VisualID currentVisualId = 0; if (widget->testAttribute(Qt::WA_WState_Created)) currentVisualId = XVisualIDFromVisual((Visual*)widget->x11Info().visual()); if (currentVisualId != visualId) { // The window is either not created or has the wrong visual. Either way, we need // to create a window with the correct visual and call create() on the widget: bool visible = widget->isVisible(); if (visible) widget->hide(); XVisualInfo visualInfo; visualInfo.visualid = visualId; { XVisualInfo *visualInfoPtr; int matchingCount = 0; visualInfoPtr = XGetVisualInfo(widget->x11Info().display(), VisualIDMask, &visualInfo, &matchingCount); Q_ASSERT(visualInfoPtr); // visualId really should be valid! visualInfo = *visualInfoPtr; XFree(visualInfoPtr); } Window parentWindow = RootWindow(widget->x11Info().display(), widget->x11Info().screen()); if (widget->parentWidget()) parentWindow = widget->parentWidget()->winId(); XSetWindowAttributes windowAttribs; QColormap colmap = QColormap::instance(widget->x11Info().screen()); windowAttribs.background_pixel = colmap.pixel(widget->palette().color(widget->backgroundRole())); windowAttribs.border_pixel = colmap.pixel(Qt::black); unsigned int valueMask = CWBackPixel|CWBorderPixel; if (alphaSize > 0) { windowAttribs.colormap = XCreateColormap(widget->x11Info().display(), parentWindow, visualInfo.visual, AllocNone); valueMask |= CWColormap; } Window window = XCreateWindow(widget->x11Info().display(), parentWindow, widget->x(), widget->y(), widget->width(), widget->height(), 0, visualInfo.depth, InputOutput, visualInfo.visual, valueMask, &windowAttribs); // This is a nasty hack to get round the fact that we can't be a friend of QWidget: qt_set_winid_on_widget(widget, window); if (visible) widget->show(); } // At this point, the widget's window should be created and have the correct visual. Now we // just need to create the EGL surface for it: EGLSurface surf = eglCreateWindowSurface(QEgl::display(), config, (EGLNativeWindowType)widget->winId(), 0); if (surf == EGL_NO_SURFACE) qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); return surf; } if (x11PixmapData) { // X11 Pixmaps are only created with a depth, so that's all we need to check EGLint configDepth; eglGetConfigAttrib(QEgl::display(), config, EGL_BUFFER_SIZE , &configDepth); if (x11PixmapData->depth() != configDepth) { // The bit depths are wrong which means the EGLConfig isn't compatable with // this pixmap. So we need to replace the pixmap's existing data with a new // one which is created with the correct depth: #ifndef QT_NO_XRENDER if (configDepth == 32) { qWarning("Warning: EGLConfig's depth (32) != pixmap's depth (%d), converting to ARGB32", x11PixmapData->depth()); x11PixmapData->convertToARGB32(true); } else #endif { qWarning("Warning: EGLConfig's depth (%d) != pixmap's depth (%d)", configDepth, x11PixmapData->depth()); } } QEglProperties surfaceAttribs; // If the pixmap can't be bound to a texture, it's pretty useless surfaceAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D); if (alphaSize > 0) surfaceAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA); else surfaceAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB); EGLSurface surf = eglCreatePixmapSurface(QEgl::display(), config, (EGLNativePixmapType) x11PixmapData->handle(), surfaceAttribs.properties()); x11PixmapData->gl_surface = (void*)surf; QImagePixmapCleanupHooks::enableCleanupHooks(x11PixmapData); return surf; } return EGL_NO_SURFACE; }
void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext) { Q_D(QGLWidget); if (context == 0) { qWarning("QGLWidget::setContext: Cannot set null context"); return; } if (!context->deviceIsPixmap() && context->device() != this) { qWarning("QGLWidget::setContext: Context must refer to this widget"); return; } if (d->glcx) d->glcx->doneCurrent(); QGLContext* oldcx = d->glcx; d->glcx = context; if (parentWidget()) { // force creation of delay-created widgets parentWidget()->winId(); if (parentWidget()->x11Info().screen() != x11Info().screen()) d_func()->xinfo = parentWidget()->d_func()->xinfo; } bool visible = isVisible(); if (visible) hide(); XVisualInfo vi; int err = XMatchVisualInfo(x11Info().display(), x11Info().screen(), x11Info().depth(), TrueColor, &vi); if (err == 0) { qWarning("Error: Couldn't get a matching X visual for format"); return; } XSetWindowAttributes a; Window p = RootWindow(X11->display, vi.screen); if (parentWidget()) p = parentWidget()->winId(); QColormap colmap = QColormap::instance(vi.screen); a.background_pixel = colmap.pixel(palette().color(backgroundRole())); a.border_pixel = colmap.pixel(Qt::black); Window w = XCreateWindow(X11->display, p, x(), y(), width(), height(), 0, vi.depth, InputOutput, vi.visual, CWBackPixel|CWBorderPixel, &a); if (deleteOldContext) delete oldcx; oldcx = 0; create(w); // Create with the ID of the window we've just created d->eglSurfaceWindowId = w; // Remember the window id we created the surface for if (visible) show(); bool createFailed = false; if (!d->glcx->isValid()) { if (!d->glcx->create(shareContext ? shareContext : oldcx)) createFailed = true; } if (createFailed) { if (deleteOldContext) delete oldcx; return; } if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) { if (deleteOldContext) delete oldcx; return; } d->glcx->setWindowCreated(true); }