1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the opengl module of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
33
#include "qapplication.h"
34
#include "qcolormap.h"
35
#include "qdesktopwidget.h"
39
#include <private/qfontengine_p.h>
40
#include <private/qt_x11_p.h>
43
#define INT8 dummy_INT8
44
#define INT32 dummy_INT32
49
#include <X11/Xutil.h>
51
#include <X11/Xatom.h>
53
extern Drawable qt_x11Handle(const QPaintDevice *pd);
54
extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
56
#ifndef GLX_ARB_multisample
57
#define GLX_SAMPLE_BUFFERS_ARB 100000
58
#define GLX_SAMPLES_ARB 100001
62
The choose_cmap function is internal and used by QGLWidget::setContext()
63
and GLX (not Windows). If the application can't find any sharable
64
colormaps, it must at least create as few colormaps as possible. The
65
dictionary solution below ensures only one colormap is created per visual.
66
Colormaps are also deleted when the application terminates.
75
XStandardColormap scmap;
78
CMapEntry::CMapEntry()
85
CMapEntry::~CMapEntry()
88
XFreeColormap(X11->display, cmap);
92
typedef QHash<int, CMapEntry *> CMapEntryHash;
93
Q_GLOBAL_STATIC(CMapEntryHash, cmap_hash)
95
static bool mesa_gl = false;
96
static bool first_time = true;
98
typedef QHash<int, QMap<int, QRgb> > GLCMapHash;
99
Q_GLOBAL_STATIC(GLCMapHash, qglcmap_hash)
101
static void cleanup_cmaps()
103
CMapEntryHash *hash = cmap_hash();
104
QHash<int, CMapEntry *>::ConstIterator it = hash->constBegin();
105
while (it != hash->constEnd()) {
112
static Colormap choose_cmap(Display *dpy, XVisualInfo *vi)
115
const char *v = glXQueryServerString(dpy, vi->screen, GLX_VERSION);
117
mesa_gl = (strstr(v, "Mesa") != 0);
118
qAddPostRoutine(cleanup_cmaps);
122
CMapEntryHash *hash = cmap_hash();
123
CMapEntryHash::ConstIterator it = hash->find((long) vi->visualid + (vi->screen * 256));
124
if (it != hash->constEnd())
125
return it.value()->cmap; // found colormap for visual
128
XVisualIDFromVisual((Visual *) QX11Info::appVisual(vi->screen))) {
129
// qDebug("Using x11AppColormap");
130
return QX11Info::appColormap(vi->screen);
133
CMapEntry *x = new CMapEntry();
135
XStandardColormap *c;
138
// qDebug("Choosing cmap for vID %0x", vi->visualid);
140
if (mesa_gl) { // we're using MesaGL
141
Atom hp_cmaps = XInternAtom(dpy, "_HP_RGB_SMOOTH_MAP_LIST", true);
142
if (hp_cmaps && vi->visual->c_class == TrueColor && vi->depth == 8) {
143
if (XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n,
146
while (i < n && x->cmap == 0) {
147
if (c[i].visualid == vi->visual->visualid) {
148
x->cmap = c[i].colormap;
150
//qDebug("Using HP_RGB scmap");
160
if (XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n,
161
XA_RGB_DEFAULT_MAP)) {
162
for (int i = 0; i < n && x->cmap == 0; ++i) {
169
continue; // invalid stdcmap
170
if (c[i].visualid == vi->visualid) {
171
x->cmap = c[i].colormap;
173
//qDebug("Using RGB_DEFAULT scmap");
179
if (!x->cmap) { // no shared cmap found
180
x->cmap = XCreateColormap(dpy, RootWindow(dpy,vi->screen), vi->visual,
183
// qDebug("Allocating cmap");
186
// associate cmap with visualid
187
hash->insert((long) vi->visualid + (vi->screen * 256), x);
198
static QVector<TransColor> trans_colors;
199
static int trans_colors_init = false;
202
static void find_trans_colors()
211
trans_colors_init = true;
213
Display* appDisplay = X11->display;
217
for (scr = 0; scr < ScreenCount(appDisplay); scr++) {
218
QWidget* rootWin = QApplication::desktop()->screen(scr);
220
return; // Should not happen
221
Atom overlayVisualsAtom = XInternAtom(appDisplay,
222
"SERVER_OVERLAY_VISUALS", True);
223
if (overlayVisualsAtom == XNone)
224
return; // Server has no overlays
230
OverlayProp* overlayProps = 0;
231
int res = XGetWindowProperty(appDisplay, rootWin->winId(),
232
overlayVisualsAtom, 0, 10000, False,
233
overlayVisualsAtom, &actualType,
234
&actualFormat, &nItems, &bytesAfter,
235
(uchar**)&overlayProps);
237
if (res != Success || actualType != overlayVisualsAtom
238
|| actualFormat != 32 || nItems < 4 || !overlayProps)
239
return; // Error reading property
241
int numProps = nItems / 4;
242
trans_colors.resize(lastsize + numProps);
244
for (int i = 0; i < numProps; i++) {
245
if (overlayProps[i].type == 1) {
246
trans_colors[j].vis = (VisualID)overlayProps[i].visual;
247
trans_colors[j].screen = scr;
248
trans_colors[j].color = (int)overlayProps[i].value;
254
trans_colors.resize(lastsize);
258
/*****************************************************************************
259
QGLFormat UNIX/GLX-specific code
260
*****************************************************************************/
262
bool QGLFormat::hasOpenGL()
264
return glXQueryExtension(X11->display, 0, 0) != 0;
268
bool QGLFormat::hasOpenGLOverlays()
270
if (!trans_colors_init)
272
return trans_colors.size() > 0;
275
/*****************************************************************************
276
QGLContext UNIX/GLX-specific code
277
*****************************************************************************/
279
bool QGLContext::chooseContext(const QGLContext* shareContext)
282
const QX11Info *xinfo = qt_x11Info(d->paintDevice);
284
Display* disp = xinfo->display();
285
d->vi = chooseVisual();
289
if (deviceIsPixmap() &&
290
(((XVisualInfo*)d->vi)->depth != xinfo->depth() ||
291
((XVisualInfo*)d->vi)->screen != xinfo->screen()))
294
XVisualInfo appVisInfo;
295
memset(&appVisInfo, 0, sizeof(XVisualInfo));
296
appVisInfo.visualid = XVisualIDFromVisual((Visual *) xinfo->visual());
297
appVisInfo.screen = xinfo->screen();
299
d->vi = XGetVisualInfo(disp, VisualIDMask | VisualScreenMask, &appVisInfo, &nvis);
304
glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_USE_GL, &useGL);
306
return false; //# Chickening out already...
309
glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_LEVEL, &res);
310
d->glFormat.setPlane(res);
311
glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_DOUBLEBUFFER, &res);
312
d->glFormat.setDoubleBuffer(res);
313
glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_DEPTH_SIZE, &res);
314
d->glFormat.setDepth(res);
315
if (d->glFormat.depth())
316
d->glFormat.setDepthBufferSize(res);
317
glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_RGBA, &res);
318
d->glFormat.setRgba(res);
319
glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_ALPHA_SIZE, &res);
320
d->glFormat.setAlpha(res);
321
if (d->glFormat.alpha())
322
d->glFormat.setAlphaBufferSize(res);
323
glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_ACCUM_RED_SIZE, &res);
324
d->glFormat.setAccum(res);
325
if (d->glFormat.accum())
326
d->glFormat.setAccumBufferSize(res);
327
glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_STENCIL_SIZE, &res);
328
d->glFormat.setStencil(res);
329
if (d->glFormat.stencil())
330
d->glFormat.setStencilBufferSize(res);
331
glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_STEREO, &res);
332
d->glFormat.setStereo(res);
333
glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_SAMPLE_BUFFERS_ARB, &res);
334
d->glFormat.setSampleBuffers(res);
335
if (d->glFormat.sampleBuffers()) {
336
glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_SAMPLES_ARB, &res);
337
d->glFormat.setSamples(res);
340
Bool direct = format().directRendering() ? True : False;
343
(!shareContext->isValid() || !shareContext->d_func()->cx)) {
344
qWarning("QGLContext::chooseContext(): Cannot share with invalid context");
348
// 1. Sharing between rgba and color-index will give wrong colors.
349
// 2. Contexts cannot be shared btw. direct/non-direct renderers.
350
// 3. Pixmaps cannot share contexts that are set up for direct rendering.
351
if (shareContext && (format().rgba() != shareContext->format().rgba() ||
353
glXIsDirect(disp, (GLXContext)shareContext->d_func()->cx))))
358
d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi,
359
(GLXContext)shareContext->d_func()->cx, direct);
362
const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
366
d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi, NULL, direct);
369
d->glFormat.setDirectRendering(glXIsDirect(disp, (GLXContext)d->cx));
370
if (deviceIsPixmap()) {
371
#if defined(GLX_MESA_pixmap_colormap) && defined(QGL_USE_MESA_EXT)
372
d->gpm = glXCreateGLXPixmapMESA(disp, (XVisualInfo *)d->vi,
373
qt_x11Handle(d->paintDevice),
374
choose_cmap(disp, (XVisualInfo *)d->vi));
376
d->gpm = (quint32)glXCreateGLXPixmap(disp, (XVisualInfo *)d->vi,
377
qt_x11Handle(d->paintDevice));
387
<strong>X11 only</strong>: This virtual function tries to find a
388
visual that matches the format, reducing the demands if the original
389
request cannot be met.
391
The algorithm for reducing the demands of the format is quite
392
simple-minded, so override this method in your subclass if your
393
application has spcific requirements on visual selection.
398
void *QGLContext::chooseVisual()
401
static int bufDepths[] = { 8, 4, 2, 1 }; // Try 16, 12 also?
402
//todo: if pixmap, also make sure that vi->depth == pixmap->depth
406
QGLFormat fmt = format();
407
bool tryDouble = !fmt.doubleBuffer(); // Some GL impl's only have double
408
bool triedDouble = false;
409
bool triedSample = false;
410
if (fmt.sampleBuffers())
411
fmt.setSampleBuffers(QGLExtensions::glExtensions & QGLExtensions::SampleBuffers);
412
while(!fail && !(vis = tryVisual(fmt, bufDepths[i]))) {
413
if (!fmt.rgba() && bufDepths[i] > 1) {
418
fmt.setDoubleBuffer(true);
422
} else if (triedDouble) {
423
fmt.setDoubleBuffer(false);
426
if (!triedSample && fmt.sampleBuffers()) {
427
fmt.setSampleBuffers(false);
432
fmt.setStereo(false);
440
fmt.setStencil(false);
451
if (fmt.doubleBuffer()) {
452
fmt.setDoubleBuffer(false);
466
<strong>X11 only</strong>: This virtual function chooses a visual
467
that matches the OpenGL \link format() format\endlink. Reimplement this
468
function in a subclass if you need a custom visual.
473
void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth)
478
spec[i++] = GLX_LEVEL;
479
spec[i++] = f.plane();
480
const QX11Info *xinfo = qt_x11Info(d->paintDevice);
482
#if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
483
static bool useTranspExt = false;
484
static bool useTranspExtChecked = false;
485
if (f.plane() && !useTranspExtChecked && d->paintDevice) {
486
QByteArray estr(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
487
useTranspExt = estr.contains("GLX_EXT_visual_info");
488
//# (A bit simplistic; that could theoretically be a substring)
490
QByteArray cstr(glXGetClientString(xinfo->display(), GLX_VENDOR));
491
useTranspExt = !cstr.contains("Xi Graphics"); // bug workaround
493
// bug workaround - some systems (eg. FireGL) refuses to return an overlay
494
// visual if the GLX_TRANSPARENT_TYPE_EXT attribute is specfied, even if
495
// the implementation supports transparent overlays
496
int tmpSpec[] = { GLX_LEVEL, f.plane(), GLX_TRANSPARENT_TYPE_EXT,
497
f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT,
499
XVisualInfo * vinf = glXChooseVisual(xinfo->display(), xinfo->screen(), tmpSpec);
501
useTranspExt = false;
506
useTranspExtChecked = true;
508
if (f.plane() && useTranspExt) {
509
// Required to avoid non-transparent overlay visual(!) on some systems
510
spec[i++] = GLX_TRANSPARENT_TYPE_EXT;
511
spec[i++] = f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT;
515
if (f.doubleBuffer())
516
spec[i++] = GLX_DOUBLEBUFFER;
518
spec[i++] = GLX_DEPTH_SIZE;
519
spec[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize();
522
spec[i++] = GLX_STEREO;
525
spec[i++] = GLX_STENCIL_SIZE;
526
spec[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize();
529
spec[i++] = GLX_RGBA;
530
spec[i++] = GLX_RED_SIZE;
532
spec[i++] = GLX_GREEN_SIZE;
534
spec[i++] = GLX_BLUE_SIZE;
537
spec[i++] = GLX_ALPHA_SIZE;
538
spec[i++] = f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize();
541
spec[i++] = GLX_ACCUM_RED_SIZE;
542
spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
543
spec[i++] = GLX_ACCUM_GREEN_SIZE;
544
spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
545
spec[i++] = GLX_ACCUM_BLUE_SIZE;
546
spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
548
spec[i++] = GLX_ACCUM_ALPHA_SIZE;
549
spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
553
spec[i++] = GLX_BUFFER_SIZE;
554
spec[i++] = bufDepth;
557
if (f.sampleBuffers()) {
558
spec[i++] = GLX_SAMPLE_BUFFERS_ARB;
560
spec[i++] = GLX_SAMPLES_ARB;
561
spec[i++] = f.samples() == -1 ? 4 : f.samples();
565
return glXChooseVisual(xinfo->display(), xinfo->screen(), spec);
569
void QGLContext::reset()
574
const QX11Info *xinfo = qt_x11Info(d->paintDevice);
577
glXDestroyGLXPixmap(xinfo->display(), (GLXPixmap)d->gpm);
579
glXDestroyContext(xinfo->display(), (GLXContext)d->cx);
587
d->transpColor = QColor();
592
void QGLContext::makeCurrent()
596
qWarning("QGLContext::makeCurrent(): Cannot make invalid context current.");
599
const QX11Info *xinfo = qt_x11Info(d->paintDevice);
601
if (deviceIsPixmap())
602
ok = glXMakeCurrent(xinfo->display(), (GLXPixmap)d->gpm, (GLXContext)d->cx);
605
ok = glXMakeCurrent(xinfo->display(), ((QWidget *)d->paintDevice)->winId(),
608
qWarning("QGLContext::makeCurrent(): Failed.");
613
void QGLContext::doneCurrent()
616
glXMakeCurrent(qt_x11Info(d->paintDevice)->display(), 0, 0);
621
void QGLContext::swapBuffers() const
623
Q_D(const QGLContext);
626
if (!deviceIsPixmap())
627
glXSwapBuffers(qt_x11Info(d->paintDevice)->display(),
628
static_cast<QWidget *>(d->paintDevice)->winId());
631
QColor QGLContext::overlayTransparentColor() const
633
Q_D(const QGLContext);
635
if (!trans_colors_init)
638
VisualID myVisualId = ((XVisualInfo*)d->vi)->visualid;
639
int myScreen = ((XVisualInfo*)d->vi)->screen;
640
for (int i = 0; i < (int)trans_colors.size(); i++) {
641
if (trans_colors[i].vis == myVisualId &&
642
trans_colors[i].screen == myScreen) {
644
col.pixel = trans_colors[i].color;
645
col.red = col.green = col.blue = 0;
647
Display *dpy = qt_x11Info(d->paintDevice)->display();
648
if (col.pixel > (uint) ((XVisualInfo *)d->vi)->colormap_size - 1)
649
col.pixel = ((XVisualInfo *)d->vi)->colormap_size - 1;
650
XQueryColor(dpy, choose_cmap(dpy, (XVisualInfo *) d->vi), &col);
651
uchar r = (uchar)((col.red / 65535.0) * 255.0 + 0.5);
652
uchar g = (uchar)((col.green / 65535.0) * 255.0 + 0.5);
653
uchar b = (uchar)((col.blue / 65535.0) * 255.0 + 0.5);
654
return QColor(qRgb(r,g,b));
658
return QColor(); // Invalid color
662
uint QGLContext::colorIndex(const QColor& c) const
664
Q_D(const QGLContext);
665
int screen = ((XVisualInfo *)d->vi)->screen;
666
QColormap colmap = QColormap::instance(screen);
669
&& colmap.pixel(c) == colmap.pixel(overlayTransparentColor()))
670
return colmap.pixel(c); // Special; don't look-up
671
if (((XVisualInfo*)d->vi)->visualid ==
672
XVisualIDFromVisual((Visual *) QX11Info::appVisual(screen)))
673
return colmap.pixel(c); // We're using QColor's cmap
675
XVisualInfo *info = (XVisualInfo *) d->vi;
676
CMapEntryHash *hash = cmap_hash();
677
CMapEntryHash::ConstIterator it = hash->find((long) info->visualid + (info->screen * 256));
679
if (it != hash->constEnd())
681
if (x && !x->alloc) { // It's a standard colormap
682
int rf = (int)(((float)c.red() * (x->scmap.red_max+1))/256.0);
683
int gf = (int)(((float)c.green() * (x->scmap.green_max+1))/256.0);
684
int bf = (int)(((float)c.blue() * (x->scmap.blue_max+1))/256.0);
685
uint p = x->scmap.base_pixel
686
+ (rf * x->scmap.red_mult)
687
+ (gf * x->scmap.green_mult)
688
+ (bf * x->scmap.blue_mult);
691
QMap<int, QRgb> &cmap = (*qglcmap_hash())[(long)info->visualid];
693
// already in the map?
694
QRgb target = c.rgb();
695
QMap<int, QRgb>::Iterator it = cmap.begin();
696
for (; it != cmap.end(); ++it) {
701
// need to alloc color
702
unsigned long plane_mask[2];
703
unsigned long color_map_entry;
704
if (!XAllocColorCells (QX11Info::display(), x->cmap, true, plane_mask, 0,
705
&color_map_entry, 1))
706
return colmap.pixel(c);
709
col.flags = DoRed | DoGreen | DoBlue;
710
col.pixel = color_map_entry;
711
col.red = (ushort)((qRed(c.rgb()) / 255.0) * 65535.0 + 0.5);
712
col.green = (ushort)((qGreen(c.rgb()) / 255.0) * 65535.0 + 0.5);
713
col.blue = (ushort)((qBlue(c.rgb()) / 255.0) * 65535.0 + 0.5);
714
XStoreColor(QX11Info::display(), x->cmap, &col);
716
cmap.insert(color_map_entry, target);
717
return color_map_entry;
723
#ifndef QT_NO_FONTCONFIG
725
This is basically a substitute for glxUseXFont() which can only
726
handle XLFD fonts. This version relies on freetype to render the
727
glyphs, but it works with all fonts that fontconfig provides - both
728
antialiased and aliased bitmap and outline fonts.
730
static void qgl_use_font(QFontEngineFT *engine, int first, int count, int listBase)
733
glGetFloatv(GL_CURRENT_COLOR, color);
735
// save the pixel unpack state
736
GLint gl_swapbytes, gl_lsbfirst, gl_rowlength, gl_skiprows, gl_skippixels, gl_alignment;
737
glGetIntegerv (GL_UNPACK_SWAP_BYTES, &gl_swapbytes);
738
glGetIntegerv (GL_UNPACK_LSB_FIRST, &gl_lsbfirst);
739
glGetIntegerv (GL_UNPACK_ROW_LENGTH, &gl_rowlength);
740
glGetIntegerv (GL_UNPACK_SKIP_ROWS, &gl_skiprows);
741
glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &gl_skippixels);
742
glGetIntegerv (GL_UNPACK_ALIGNMENT, &gl_alignment);
744
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
745
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
746
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
747
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
748
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
749
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
751
FcBool antialiased = True;
752
FcPatternGetBool(engine->pattern(), FC_ANTIALIAS, 0, &antialiased);
753
FT_Face face = engine->lockFace();
755
// start generating font glyphs
756
for (int i = first; i < count; ++i) {
757
int list = listBase + i;
758
GLfloat x0, y0, dx, dy;
762
err = FT_Load_Glyph(face, FT_Get_Char_Index(face, i), FT_LOAD_DEFAULT);
764
qDebug("failed loading glyph %d from font", i);
767
err = FT_Render_Glyph(face->glyph, (antialiased ? ft_render_mode_normal
768
: ft_render_mode_mono));
770
qDebug("failed rendering glyph %d from font", i);
774
FT_Bitmap bm = face->glyph->bitmap;
775
x0 = face->glyph->metrics.horiBearingX >> 6;
776
y0 = (face->glyph->metrics.height - face->glyph->metrics.horiBearingY) >> 6;
777
dx = face->glyph->metrics.horiAdvance >> 6;
779
int sz = bm.pitch * bm.rows;
784
aa_glyph = new uint[sz];
786
ua_glyph = new uchar[sz];
788
// convert to GL format
789
for (int y = 0; y < bm.rows; ++y) {
790
for (int x = 0; x < bm.pitch; ++x) {
791
int c1 = y*bm.pitch + x;
792
int c2 = (bm.rows - y - 1) > 0 ? (bm.rows-y-1)*bm.pitch + x : x;
794
aa_glyph[c1] = (int(color[0]*255) << 24)
795
| (int(color[1]*255) << 16)
796
| (int(color[2]*255) << 8) | bm.buffer[c2];
798
ua_glyph[c1] = bm.buffer[c2];
803
glNewList(list, GL_COMPILE);
805
// calling glBitmap() is just a trick to move the current
806
// raster pos, since glGet*() won't work in display lists
807
glBitmap(0, 0, 0, 0, x0, -y0, 0);
808
glDrawPixels(bm.pitch, bm.rows, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, aa_glyph);
809
glBitmap(0, 0, 0, 0, dx-x0, y0, 0);
811
glBitmap(bm.pitch*8, bm.rows, -x0, y0, dx, dy, ua_glyph);
814
antialiased ? delete[] aa_glyph : delete[] ua_glyph;
817
engine->unlockFace();
819
// restore pixel unpack settings
820
glPixelStorei(GL_UNPACK_SWAP_BYTES, gl_swapbytes);
821
glPixelStorei(GL_UNPACK_LSB_FIRST, gl_lsbfirst);
822
glPixelStorei(GL_UNPACK_ROW_LENGTH, gl_rowlength);
823
glPixelStorei(GL_UNPACK_SKIP_ROWS, gl_skiprows);
824
glPixelStorei(GL_UNPACK_SKIP_PIXELS, gl_skippixels);
825
glPixelStorei(GL_UNPACK_ALIGNMENT, gl_alignment);
830
void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
833
QFontEngine *engine = f.d->engineForScript(QUnicodeTables::Common);
835
if (engine->type() == QFontEngine::Multi)
836
engine = static_cast<QFontEngineMulti *>(engine)->engine(0);
837
#ifndef QT_NO_FONTCONFIG
838
if(engine->type() == QFontEngine::Freetype) {
839
qgl_use_font(static_cast<QFontEngineFT *>(engine), 0, 256, listBase);
843
// glXUseXFont() only works with XLFD font structures and a few GL
844
// drivers crash if 0 is passed as the font handle
845
f.setStyleStrategy(QFont::OpenGLCompatible);
846
if (f.handle() && engine->type() == QFontEngine::XLFD)
847
glXUseXFont(static_cast<Font>(f.handle()), 0, 256, listBase);
851
Returns a function pointer to the GL extension function passed in
852
\a proc. 0 is returned if a pointer to the function could not be
855
void *QGLContext::getProcAddress(const QString &proc) const
857
typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *);
858
static qt_glXGetProcAddressARB glXGetProcAddressARB = 0;
860
if (!glXGetProcAddressARB) {
861
QString glxExt(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
862
if (glxExt.contains("GLX_ARB_get_proc_address")) {
864
glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB");
865
if (!glXGetProcAddressARB)
869
return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(proc.toLatin1().data()));
872
/*****************************************************************************
873
QGLOverlayWidget (Internal overlay class for X11)
874
*****************************************************************************/
876
class QGLOverlayWidget : public QGLWidget
880
QGLOverlayWidget(const QGLFormat& format, QGLWidget* parent, const QGLWidget* shareWidget=0);
885
void resizeGL(int w, int h);
888
QGLWidget* realWidget;
891
Q_DISABLE_COPY(QGLOverlayWidget)
895
QGLOverlayWidget::QGLOverlayWidget(const QGLFormat& format, QGLWidget* parent,
896
const QGLWidget* shareWidget)
897
: QGLWidget(format, parent, shareWidget ? shareWidget->d_func()->olw : 0)
904
void QGLOverlayWidget::initializeGL()
906
QColor transparentColor = context()->overlayTransparentColor();
907
if (transparentColor.isValid())
908
qglClearColor(transparentColor);
910
qWarning("QGLOverlayWidget::initializeGL(): Could not get transparent color");
911
realWidget->initializeOverlayGL();
915
void QGLOverlayWidget::resizeGL(int w, int h)
917
glViewport(0, 0, w, h);
918
realWidget->resizeOverlayGL(w, h);
922
void QGLOverlayWidget::paintGL()
924
realWidget->paintOverlayGL();
928
#include "qgl_x11.moc"
930
/*****************************************************************************
931
QGLWidget UNIX/GLX-specific code
932
*****************************************************************************/
933
void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget *shareWidget)
936
QGLExtensions::init();
940
if (!context->device())
941
context->setDevice(q);
944
q->setContext(context, shareWidget->context());
946
q->setContext(context);
947
q->setAttribute(Qt::WA_NoSystemBackground, true);
949
if (q->isValid() && context->format().hasOverlay()) {
950
QString olwName = q->objectName();
951
olwName += "-QGL_internal_overlay_widget";
952
olw = new QGLOverlayWidget(QGLFormat::defaultOverlayFormat(), q, shareWidget);
953
olw->setObjectName(olwName);
954
if (olw->isValid()) {
955
olw->setAutoBufferSwap(false);
956
olw->setFocusProxy(q);
961
glcx->d_func()->glFormat.setOverlay(false);
966
bool QGLWidgetPrivate::renderCxPm(QPixmap* pm)
969
if (((XVisualInfo*)glcx->d_func()->vi)->depth != pm->depth())
973
#if defined(GLX_MESA_pixmap_colormap) && defined(QGL_USE_MESA_EXT)
974
glPm = glXCreateGLXPixmapMESA(X11->display,
975
(XVisualInfo*)glcx->vi,
976
(Pixmap)pm->handle(),
977
choose_cmap(pm->X11->display,
978
(XVisualInfo*)glcx->vi));
980
glPm = (quint32)glXCreateGLXPixmap(X11->display,
981
(XVisualInfo*)glcx->d_func()->vi,
982
(Pixmap)pm->handle());
985
if (!glXMakeCurrent(X11->display, glPm, (GLXContext)glcx->d_func()->cx)) {
986
glXDestroyGLXPixmap(X11->display, glPm);
990
glDrawBuffer(GL_FRONT);
991
if (!glcx->initialized())
993
q->resizeGL(pm->width(), pm->height());
997
glXDestroyGLXPixmap(X11->display, glPm);
998
q->resizeGL(q->width(), q->height());
1003
Free up any allocated colormaps. This fn is only called for
1006
void QGLWidgetPrivate::cleanupColormaps()
1008
if (!cmap.handle()) {
1011
XFreeColormap(X11->display, (Colormap) cmap.handle());
1017
bool QGLWidget::event(QEvent *e)
1019
return QWidget::event(e);
1023
void QGLWidget::setMouseTracking(bool enable)
1027
d->olw->setMouseTracking(enable);
1028
QWidget::setMouseTracking(enable);
1032
void QGLWidget::resizeEvent(QResizeEvent *)
1038
if (!d->glcx->initialized())
1041
resizeGL(width(), height());
1043
d->olw->setGeometry(rect());
1046
const QGLContext* QGLWidget::overlayContext() const
1048
Q_D(const QGLWidget);
1050
return d->olw->context();
1056
void QGLWidget::makeOverlayCurrent()
1060
d->olw->makeCurrent();
1064
void QGLWidget::updateOverlayGL()
1074
Sets a new QGLContext, \a context, for this QGLWidget, using the
1075
shared context, \a shareContext. If \a deleteOldContext is true,
1076
the original context is deleted; otherwise it is overridden.
1078
void QGLWidget::setContext(QGLContext *context,
1079
const QGLContext* shareContext,
1080
bool deleteOldContext)
1084
qWarning("QGLWidget::setContext: Cannot set null context");
1087
if (!context->deviceIsPixmap() && context->device() != this) {
1088
qWarning("QGLWidget::setContext: Context must refer to this widget");
1093
d->glcx->doneCurrent();
1094
QGLContext* oldcx = d->glcx;
1097
bool createFailed = false;
1098
if (!d->glcx->isValid()) {
1099
if (!d->glcx->create(shareContext ? shareContext : oldcx))
1100
createFailed = true;
1103
if (deleteOldContext)
1108
if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
1109
if (deleteOldContext)
1114
bool visible = isVisible();
1118
XVisualInfo *vi = (XVisualInfo*)d->glcx->d_func()->vi;
1119
XSetWindowAttributes a;
1121
QColormap colmap = QColormap::instance(vi->screen);
1122
a.colormap = choose_cmap(QX11Info::display(), vi); // find best colormap
1123
a.background_pixel = colmap.pixel(palette().color(backgroundRole()));
1124
a.border_pixel = colmap.pixel(Qt::black);
1125
Window p = RootWindow(X11->display, vi->screen);
1127
p = parentWidget()->winId();
1129
Window w = XCreateWindow(X11->display, p, x(), y(), width(), height(),
1130
0, vi->depth, InputOutput, vi->visual,
1131
CWBackPixel|CWBorderPixel|CWColormap, &a);
1136
if (XGetWMColormapWindows(X11->display, window()->winId(),
1138
cmw = new Window[count+1];
1139
memcpy((char *)cmw, (char *)cmwret, sizeof(Window)*count);
1140
XFree((char *)cmwret);
1142
for (i=0; i<count; i++) {
1143
if (cmw[i] == winId()) { // replace old window
1148
if (i >= count) // append new window
1152
cmw = new Window[count];
1156
#if defined(GLX_MESA_release_buffers) && defined(QGL_USE_MESA_EXT)
1157
if (oldcx && oldcx->windowCreated())
1158
glXReleaseBuffersMESA(X11->display, winId());
1160
if (deleteOldContext)
1166
XSetWMColormapWindows(X11->display, window()->winId(), cmw,
1170
// calling QWidget::create() will always result in a new paint
1171
// engine being created - get rid of it and replace it with our
1176
XFlush(X11->display);
1177
d->glcx->setWindowCreated(true);
1180
const QGLColormap & QGLWidget::colormap() const
1182
Q_D(const QGLWidget);
1187
Store color values in the given colormap.
1189
static void qStoreColors(QWidget * tlw, Colormap cmap,
1190
const QGLColormap & cols)
1196
for (int i = 0; i < cols.size(); i++) {
1197
color = cols.entryRgb(i);
1199
c.red = (ushort)((qRed(color) / 255.0) * 65535.0 + 0.5);
1200
c.green = (ushort)((qGreen(color) / 255.0) * 65535.0 + 0.5);
1201
c.blue = (ushort)((qBlue(color) / 255.0) * 65535.0 + 0.5);
1202
c.flags = DoRed | DoGreen | DoBlue;
1203
XStoreColor(X11->display, cmap, &c);
1208
Check whether the given visual supports dynamic colormaps or not.
1210
static bool qCanAllocColors(QWidget * w)
1212
bool validVisual = false;
1216
XVisualInfo * visuals;
1217
VisualID id = XVisualIDFromVisual((Visual *) w->window()->x11Info().visual());
1219
mask = VisualScreenMask;
1220
templ.screen = w->x11Info().screen();
1221
visuals = XGetVisualInfo(X11->display, mask, &templ, &numVisuals);
1223
for (int i = 0; i < numVisuals; i++) {
1224
if (visuals[i].visualid == id) {
1225
switch (visuals[i].c_class) {
1230
validVisual = false;
1248
void QGLWidget::setColormap(const QGLColormap & c)
1251
QWidget * tlw = window(); // must return a valid widget
1254
if (!d->cmap.handle())
1257
if (!qCanAllocColors(this)) {
1258
qWarning("QGLWidget::setColormap: Cannot create a read/write "
1259
"colormap for this visual");
1263
// If the child GL widget is not of the same visual class as the
1264
// toplevel widget we will get in trouble..
1265
Window wid = tlw->winId();
1266
Visual * vis = (Visual *) tlw->x11Info().visual();;
1267
VisualID cvId = XVisualIDFromVisual((Visual *) x11Info().visual());
1268
VisualID tvId = XVisualIDFromVisual((Visual *) tlw->x11Info().visual());
1271
vis = (Visual *) x11Info().visual();
1274
if (!d->cmap.handle()) // allocate a cmap if necessary
1275
d->cmap.setHandle(XCreateColormap(X11->display, wid, vis, AllocAll));
1277
qStoreColors(this, (Colormap) d->cmap.handle(), c);
1278
XSetWindowColormap(X11->display, wid, (Colormap) d->cmap.handle());
1280
// tell the wm that this window has a special colormap
1284
if (XGetWMColormapWindows(X11->display, tlw->winId(), &cmwret, &count))
1286
cmw = new Window[count+1];
1287
memcpy((char *) cmw, (char *) cmwret, sizeof(Window) * count);
1288
XFree((char *) cmwret);
1290
for (i = 0; i < count; i++) {
1291
if (cmw[i] == winId()) {
1295
if (i >= count) // append new window only if not in the list
1296
cmw[count++] = winId();
1299
cmw = new Window[count];
1302
XSetWMColormapWindows(X11->display, tlw->winId(), cmw, count);
1306
void QGLExtensions::init()
1308
static bool init_done = false;
1315
int attribs[] = { GLX_RGBA, XNone };
1316
int attribs_dbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, XNone };
1318
XSetWindowAttributes attr;
1322
XVisualInfo *visinfo;
1323
int width = 10, height = 10;
1325
root = RootWindow(X11->display, 0);
1327
visinfo = glXChooseVisual(X11->display, 0, attribs);
1329
visinfo = glXChooseVisual(X11->display, 0, attribs_dbl);
1331
qDebug("QGLExtensions: couldn't find any RGB visuals.");
1336
attr.background_pixel = 0;
1337
attr.border_pixel = 0;
1338
attr.colormap = XCreateColormap(X11->display, root, visinfo->visual, AllocNone);
1339
attr.event_mask = StructureNotifyMask | ExposureMask;
1340
mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
1341
win = XCreateWindow(X11->display, root, 0, 0, width, height, 0,
1342
visinfo->depth, InputOutput, visinfo->visual, mask, &attr);
1344
ctx = glXCreateContext(X11->display, visinfo, NULL, true);
1350
if (glXMakeCurrent(X11->display, win, ctx))
1353
qDebug("QGLExtensions: glXMakeCurrent() failed.");
1354
glXDestroyContext(X11->display, ctx);
1356
qDebug("QGLExtensions: glXCreateContext failed.");
1358
XDestroyWindow(X11->display, win);
1359
XFreeColormap(X11->display, attr.colormap);