~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/opengl/qgl_x11.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the opengl module of the Qt Toolkit.
 
6
**
 
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.
 
10
**
 
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.
 
15
**
 
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.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
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.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "qgl.h"
 
30
#include "qgl_p.h"
 
31
 
 
32
#include "qmap.h"
 
33
#include "qapplication.h"
 
34
#include "qcolormap.h"
 
35
#include "qdesktopwidget.h"
 
36
#include "qpixmap.h"
 
37
#include "qhash.h"
 
38
#include "qlibrary.h"
 
39
#include <private/qfontengine_p.h>
 
40
#include <private/qt_x11_p.h>
 
41
#include <qdebug.h>
 
42
 
 
43
#define INT8  dummy_INT8
 
44
#define INT32 dummy_INT32
 
45
#include <GL/glx.h>
 
46
#undef  INT8
 
47
#undef  INT32
 
48
#include <X11/Xlib.h>
 
49
#include <X11/Xutil.h>
 
50
#include <X11/Xos.h>
 
51
#include <X11/Xatom.h>
 
52
 
 
53
extern Drawable qt_x11Handle(const QPaintDevice *pd);
 
54
extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
 
55
 
 
56
#ifndef GLX_ARB_multisample
 
57
#define GLX_SAMPLE_BUFFERS_ARB  100000
 
58
#define GLX_SAMPLES_ARB         100001
 
59
#endif
 
60
 
 
61
/*
 
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.
 
67
*/
 
68
 
 
69
struct CMapEntry {
 
70
    CMapEntry();
 
71
    ~CMapEntry();
 
72
 
 
73
    Colormap                cmap;
 
74
    bool                alloc;
 
75
    XStandardColormap        scmap;
 
76
};
 
77
 
 
78
CMapEntry::CMapEntry()
 
79
{
 
80
    cmap = 0;
 
81
    alloc = false;
 
82
    scmap.colormap = 0;
 
83
}
 
84
 
 
85
CMapEntry::~CMapEntry()
 
86
{
 
87
    if (alloc)
 
88
        XFreeColormap(X11->display, cmap);
 
89
}
 
90
 
 
91
 
 
92
typedef QHash<int, CMapEntry *> CMapEntryHash;
 
93
Q_GLOBAL_STATIC(CMapEntryHash, cmap_hash)
 
94
 
 
95
static bool mesa_gl = false;
 
96
static bool first_time = true;
 
97
 
 
98
typedef QHash<int, QMap<int, QRgb> > GLCMapHash;
 
99
Q_GLOBAL_STATIC(GLCMapHash, qglcmap_hash)
 
100
 
 
101
static void cleanup_cmaps()
 
102
{
 
103
    CMapEntryHash *hash = cmap_hash();
 
104
    QHash<int, CMapEntry *>::ConstIterator it = hash->constBegin();
 
105
    while (it != hash->constEnd()) {
 
106
        delete it.value();
 
107
        ++it;
 
108
    }
 
109
    hash->clear();
 
110
}
 
111
 
 
112
static Colormap choose_cmap(Display *dpy, XVisualInfo *vi)
 
113
{
 
114
    if (first_time) {
 
115
        const char *v = glXQueryServerString(dpy, vi->screen, GLX_VERSION);
 
116
        if (v)
 
117
            mesa_gl = (strstr(v, "Mesa") != 0);
 
118
        qAddPostRoutine(cleanup_cmaps);
 
119
        first_time = false;
 
120
    }
 
121
 
 
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
 
126
 
 
127
    if (vi->visualid ==
 
128
        XVisualIDFromVisual((Visual *) QX11Info::appVisual(vi->screen))) {
 
129
        // qDebug("Using x11AppColormap");
 
130
        return QX11Info::appColormap(vi->screen);
 
131
    }
 
132
 
 
133
    CMapEntry *x = new CMapEntry();
 
134
 
 
135
    XStandardColormap *c;
 
136
    int n, i;
 
137
 
 
138
    // qDebug("Choosing cmap for vID %0x", vi->visualid);
 
139
 
 
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,
 
144
                                 hp_cmaps)) {
 
145
                i = 0;
 
146
                while (i < n && x->cmap == 0) {
 
147
                    if (c[i].visualid == vi->visual->visualid) {
 
148
                        x->cmap = c[i].colormap;
 
149
                        x->scmap = c[i];
 
150
                        //qDebug("Using HP_RGB scmap");
 
151
 
 
152
                    }
 
153
                    i++;
 
154
                }
 
155
                XFree((char *)c);
 
156
            }
 
157
        }
 
158
    }
 
159
    if (!x->cmap) {
 
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) {
 
163
                if (!c[i].red_max ||
 
164
                    !c[i].green_max ||
 
165
                    !c[i].blue_max ||
 
166
                    !c[i].red_mult ||
 
167
                    !c[i].green_mult ||
 
168
                    !c[i].blue_mult)
 
169
                    continue; // invalid stdcmap
 
170
                if (c[i].visualid == vi->visualid) {
 
171
                    x->cmap = c[i].colormap;
 
172
                    x->scmap = c[i];
 
173
                    //qDebug("Using RGB_DEFAULT scmap");
 
174
                }
 
175
            }
 
176
            XFree((char *)c);
 
177
        }
 
178
    }
 
179
    if (!x->cmap) {                                // no shared cmap found
 
180
        x->cmap = XCreateColormap(dpy, RootWindow(dpy,vi->screen), vi->visual,
 
181
                                  AllocNone);
 
182
        x->alloc = true;
 
183
        // qDebug("Allocating cmap");
 
184
    }
 
185
 
 
186
    // associate cmap with visualid
 
187
    hash->insert((long) vi->visualid + (vi->screen * 256), x);
 
188
    return x->cmap;
 
189
}
 
190
 
 
191
struct TransColor
 
192
{
 
193
    VisualID        vis;
 
194
    int                screen;
 
195
    long        color;
 
196
};
 
197
 
 
198
static QVector<TransColor> trans_colors;
 
199
static int trans_colors_init = false;
 
200
 
 
201
 
 
202
static void find_trans_colors()
 
203
{
 
204
    struct OverlayProp {
 
205
        long  visual;
 
206
        long  type;
 
207
        long  value;
 
208
        long  layer;
 
209
    };
 
210
 
 
211
    trans_colors_init = true;
 
212
 
 
213
    Display* appDisplay = X11->display;
 
214
 
 
215
    int scr;
 
216
    int lastsize = 0;
 
217
    for (scr = 0; scr < ScreenCount(appDisplay); scr++) {
 
218
        QWidget* rootWin = QApplication::desktop()->screen(scr);
 
219
        if (!rootWin)
 
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
 
225
 
 
226
        Atom actualType;
 
227
        int actualFormat;
 
228
        ulong nItems;
 
229
        ulong bytesAfter;
 
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);
 
236
 
 
237
        if (res != Success || actualType != overlayVisualsAtom
 
238
             || actualFormat != 32 || nItems < 4 || !overlayProps)
 
239
            return;                                        // Error reading property
 
240
 
 
241
        int numProps = nItems / 4;
 
242
        trans_colors.resize(lastsize + numProps);
 
243
        int j = lastsize;
 
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;
 
249
                j++;
 
250
            }
 
251
        }
 
252
        XFree(overlayProps);
 
253
        lastsize = j;
 
254
        trans_colors.resize(lastsize);
 
255
    }
 
256
}
 
257
 
 
258
/*****************************************************************************
 
259
  QGLFormat UNIX/GLX-specific code
 
260
 *****************************************************************************/
 
261
 
 
262
bool QGLFormat::hasOpenGL()
 
263
{
 
264
    return glXQueryExtension(X11->display, 0, 0) != 0;
 
265
}
 
266
 
 
267
 
 
268
bool QGLFormat::hasOpenGLOverlays()
 
269
{
 
270
    if (!trans_colors_init)
 
271
        find_trans_colors();
 
272
    return trans_colors.size() > 0;
 
273
}
 
274
 
 
275
/*****************************************************************************
 
276
  QGLContext UNIX/GLX-specific code
 
277
 *****************************************************************************/
 
278
 
 
279
bool QGLContext::chooseContext(const QGLContext* shareContext)
 
280
{
 
281
    Q_D(QGLContext);
 
282
    const QX11Info *xinfo = qt_x11Info(d->paintDevice);
 
283
 
 
284
    Display* disp = xinfo->display();
 
285
    d->vi = chooseVisual();
 
286
    if (!d->vi)
 
287
        return false;
 
288
 
 
289
    if (deviceIsPixmap() &&
 
290
         (((XVisualInfo*)d->vi)->depth != xinfo->depth() ||
 
291
          ((XVisualInfo*)d->vi)->screen != xinfo->screen()))
 
292
    {
 
293
        XFree(d->vi);
 
294
        XVisualInfo appVisInfo;
 
295
        memset(&appVisInfo, 0, sizeof(XVisualInfo));
 
296
        appVisInfo.visualid = XVisualIDFromVisual((Visual *) xinfo->visual());
 
297
        appVisInfo.screen = xinfo->screen();
 
298
        int nvis;
 
299
        d->vi = XGetVisualInfo(disp, VisualIDMask | VisualScreenMask, &appVisInfo, &nvis);
 
300
        if (!d->vi)
 
301
            return false;
 
302
 
 
303
        int useGL;
 
304
        glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_USE_GL, &useGL);
 
305
        if (!useGL)
 
306
            return false;        //# Chickening out already...
 
307
    }
 
308
    int res;
 
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);
 
338
    }
 
339
 
 
340
    Bool direct = format().directRendering() ? True : False;
 
341
 
 
342
    if (shareContext &&
 
343
         (!shareContext->isValid() || !shareContext->d_func()->cx)) {
 
344
            qWarning("QGLContext::chooseContext(): Cannot share with invalid context");
 
345
            shareContext = 0;
 
346
    }
 
347
 
 
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() ||
 
352
                          (deviceIsPixmap() &&
 
353
                           glXIsDirect(disp, (GLXContext)shareContext->d_func()->cx))))
 
354
        shareContext = 0;
 
355
 
 
356
    d->cx = 0;
 
357
    if (shareContext) {
 
358
        d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi,
 
359
                               (GLXContext)shareContext->d_func()->cx, direct);
 
360
        if (d->cx) {
 
361
            d->sharing = true;
 
362
            const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
 
363
        }
 
364
    }
 
365
    if (!d->cx)
 
366
        d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi, NULL, direct);
 
367
    if (!d->cx)
 
368
        return false;
 
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));
 
375
#else
 
376
        d->gpm = (quint32)glXCreateGLXPixmap(disp, (XVisualInfo *)d->vi,
 
377
                                              qt_x11Handle(d->paintDevice));
 
378
#endif
 
379
        if (!d->gpm)
 
380
            return false;
 
381
    }
 
382
    return true;
 
383
}
 
384
 
 
385
 
 
386
/*!
 
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.
 
390
 
 
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.
 
394
 
 
395
  \sa chooseContext()
 
396
*/
 
397
 
 
398
void *QGLContext::chooseVisual()
 
399
{
 
400
    Q_D(QGLContext);
 
401
    static int bufDepths[] = { 8, 4, 2, 1 };        // Try 16, 12 also?
 
402
    //todo: if pixmap, also make sure that vi->depth == pixmap->depth
 
403
    void* vis = 0;
 
404
    int i = 0;
 
405
    bool fail = false;
 
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) {
 
414
            i++;
 
415
            continue;
 
416
        }
 
417
        if (tryDouble) {
 
418
            fmt.setDoubleBuffer(true);
 
419
            tryDouble = false;
 
420
            triedDouble = true;
 
421
            continue;
 
422
        } else if (triedDouble) {
 
423
            fmt.setDoubleBuffer(false);
 
424
            triedDouble = false;
 
425
        }
 
426
        if (!triedSample && fmt.sampleBuffers()) {
 
427
            fmt.setSampleBuffers(false);
 
428
            triedSample = true;
 
429
            continue;
 
430
        }
 
431
        if (fmt.stereo()) {
 
432
            fmt.setStereo(false);
 
433
            continue;
 
434
        }
 
435
        if (fmt.accum()) {
 
436
            fmt.setAccum(false);
 
437
            continue;
 
438
        }
 
439
        if (fmt.stencil()) {
 
440
            fmt.setStencil(false);
 
441
            continue;
 
442
        }
 
443
        if (fmt.alpha()) {
 
444
            fmt.setAlpha(false);
 
445
            continue;
 
446
        }
 
447
        if (fmt.depth()) {
 
448
            fmt.setDepth(false);
 
449
            continue;
 
450
        }
 
451
        if (fmt.doubleBuffer()) {
 
452
            fmt.setDoubleBuffer(false);
 
453
            continue;
 
454
        }
 
455
        fail = true;
 
456
    }
 
457
    d->glFormat = fmt;
 
458
    return vis;
 
459
}
 
460
 
 
461
 
 
462
/*!
 
463
 
 
464
  \internal
 
465
 
 
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.
 
469
 
 
470
  \sa chooseContext()
 
471
*/
 
472
 
 
473
void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth)
 
474
{
 
475
    Q_D(QGLContext);
 
476
    int spec[40];
 
477
    int i = 0;
 
478
    spec[i++] = GLX_LEVEL;
 
479
    spec[i++] = f.plane();
 
480
    const QX11Info *xinfo = qt_x11Info(d->paintDevice);
 
481
 
 
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)
 
489
        if (useTranspExt) {
 
490
            QByteArray cstr(glXGetClientString(xinfo->display(), GLX_VENDOR));
 
491
            useTranspExt = !cstr.contains("Xi Graphics"); // bug workaround
 
492
            if (useTranspExt) {
 
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,
 
498
                                  XNone };
 
499
                XVisualInfo * vinf = glXChooseVisual(xinfo->display(), xinfo->screen(), tmpSpec);
 
500
                if (!vinf) {
 
501
                    useTranspExt = false;
 
502
                }
 
503
            }
 
504
        }
 
505
 
 
506
        useTranspExtChecked = true;
 
507
    }
 
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;
 
512
    }
 
513
#endif
 
514
 
 
515
    if (f.doubleBuffer())
 
516
        spec[i++] = GLX_DOUBLEBUFFER;
 
517
    if (f.depth()) {
 
518
        spec[i++] = GLX_DEPTH_SIZE;
 
519
        spec[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize();
 
520
    }
 
521
    if (f.stereo()) {
 
522
        spec[i++] = GLX_STEREO;
 
523
    }
 
524
    if (f.stencil()) {
 
525
        spec[i++] = GLX_STENCIL_SIZE;
 
526
        spec[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize();
 
527
    }
 
528
    if (f.rgba()) {
 
529
        spec[i++] = GLX_RGBA;
 
530
        spec[i++] = GLX_RED_SIZE;
 
531
        spec[i++] = 1;
 
532
        spec[i++] = GLX_GREEN_SIZE;
 
533
        spec[i++] = 1;
 
534
        spec[i++] = GLX_BLUE_SIZE;
 
535
        spec[i++] = 1;
 
536
        if (f.alpha()) {
 
537
            spec[i++] = GLX_ALPHA_SIZE;
 
538
            spec[i++] = f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize();
 
539
        }
 
540
        if (f.accum()) {
 
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();
 
547
            if (f.alpha()) {
 
548
                spec[i++] = GLX_ACCUM_ALPHA_SIZE;
 
549
                spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
 
550
            }
 
551
        }
 
552
    } else {
 
553
        spec[i++] = GLX_BUFFER_SIZE;
 
554
        spec[i++] = bufDepth;
 
555
    }
 
556
 
 
557
    if (f.sampleBuffers()) {
 
558
        spec[i++] = GLX_SAMPLE_BUFFERS_ARB;
 
559
        spec[i++] = 1;
 
560
        spec[i++] = GLX_SAMPLES_ARB;
 
561
        spec[i++] = f.samples() == -1 ? 4 : f.samples();
 
562
    }
 
563
 
 
564
    spec[i] = XNone;
 
565
    return glXChooseVisual(xinfo->display(), xinfo->screen(), spec);
 
566
}
 
567
 
 
568
 
 
569
void QGLContext::reset()
 
570
{
 
571
    Q_D(QGLContext);
 
572
    if (!d->valid)
 
573
        return;
 
574
    const QX11Info *xinfo = qt_x11Info(d->paintDevice);
 
575
    doneCurrent();
 
576
    if (d->gpm)
 
577
        glXDestroyGLXPixmap(xinfo->display(), (GLXPixmap)d->gpm);
 
578
    d->gpm = 0;
 
579
    glXDestroyContext(xinfo->display(), (GLXContext)d->cx);
 
580
    if (d->vi)
 
581
        XFree(d->vi);
 
582
    d->vi = 0;
 
583
    d->cx = 0;
 
584
    d->crWin = false;
 
585
    d->sharing = false;
 
586
    d->valid = false;
 
587
    d->transpColor = QColor();
 
588
    d->initDone = false;
 
589
}
 
590
 
 
591
 
 
592
void QGLContext::makeCurrent()
 
593
{
 
594
    Q_D(QGLContext);
 
595
    if (!d->valid) {
 
596
        qWarning("QGLContext::makeCurrent(): Cannot make invalid context current.");
 
597
        return;
 
598
    }
 
599
    const QX11Info *xinfo = qt_x11Info(d->paintDevice);
 
600
    bool ok = true;
 
601
    if (deviceIsPixmap())
 
602
        ok = glXMakeCurrent(xinfo->display(), (GLXPixmap)d->gpm, (GLXContext)d->cx);
 
603
 
 
604
    else
 
605
        ok = glXMakeCurrent(xinfo->display(), ((QWidget *)d->paintDevice)->winId(),
 
606
                             (GLXContext)d->cx);
 
607
    if (!ok)
 
608
        qWarning("QGLContext::makeCurrent(): Failed.");
 
609
    if (ok)
 
610
        currentCtx = this;
 
611
}
 
612
 
 
613
void QGLContext::doneCurrent()
 
614
{
 
615
    Q_D(QGLContext);
 
616
    glXMakeCurrent(qt_x11Info(d->paintDevice)->display(), 0, 0);
 
617
    currentCtx = 0;
 
618
}
 
619
 
 
620
 
 
621
void QGLContext::swapBuffers() const
 
622
{
 
623
    Q_D(const QGLContext);
 
624
    if (!d->valid)
 
625
        return;
 
626
    if (!deviceIsPixmap())
 
627
        glXSwapBuffers(qt_x11Info(d->paintDevice)->display(),
 
628
                       static_cast<QWidget *>(d->paintDevice)->winId());
 
629
}
 
630
 
 
631
QColor QGLContext::overlayTransparentColor() const
 
632
{
 
633
    Q_D(const QGLContext);
 
634
    if (isValid()) {
 
635
        if (!trans_colors_init)
 
636
            find_trans_colors();
 
637
 
 
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) {
 
643
                XColor col;
 
644
                col.pixel = trans_colors[i].color;
 
645
                col.red = col.green = col.blue = 0;
 
646
                col.flags = 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));
 
655
            }
 
656
        }
 
657
    }
 
658
    return QColor();                // Invalid color
 
659
}
 
660
 
 
661
 
 
662
uint QGLContext::colorIndex(const QColor& c) const
 
663
{
 
664
    Q_D(const QGLContext);
 
665
    int screen = ((XVisualInfo *)d->vi)->screen;
 
666
    QColormap colmap = QColormap::instance(screen);
 
667
    if (isValid()) {
 
668
        if (format().plane()
 
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
 
674
 
 
675
        XVisualInfo *info = (XVisualInfo *) d->vi;
 
676
        CMapEntryHash *hash = cmap_hash();
 
677
        CMapEntryHash::ConstIterator it = hash->find((long) info->visualid + (info->screen * 256));
 
678
        CMapEntry *x = 0;
 
679
        if (it != hash->constEnd())
 
680
            x = it.value();
 
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);
 
689
            return p;
 
690
        } else {
 
691
            QMap<int, QRgb> &cmap = (*qglcmap_hash())[(long)info->visualid];
 
692
 
 
693
            // already in the map?
 
694
            QRgb target = c.rgb();
 
695
            QMap<int, QRgb>::Iterator it = cmap.begin();
 
696
            for (; it != cmap.end(); ++it) {
 
697
                if ((*it) == target)
 
698
                    return it.key();
 
699
            }
 
700
 
 
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);
 
707
 
 
708
            XColor col;
 
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);
 
715
 
 
716
            cmap.insert(color_map_entry, target);
 
717
            return color_map_entry;
 
718
        }
 
719
    }
 
720
    return 0;
 
721
}
 
722
 
 
723
#ifndef QT_NO_FONTCONFIG
 
724
/*! \internal
 
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.
 
729
*/
 
730
static void qgl_use_font(QFontEngineFT *engine, int first, int count, int listBase)
 
731
{
 
732
    GLfloat color[4];
 
733
    glGetFloatv(GL_CURRENT_COLOR, color);
 
734
 
 
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);
 
743
 
 
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);
 
750
 
 
751
    FcBool antialiased = True;
 
752
    FcPatternGetBool(engine->pattern(), FC_ANTIALIAS, 0, &antialiased);
 
753
    FT_Face face = engine->lockFace();
 
754
 
 
755
    // start generating font glyphs
 
756
    for (int i = first; i < count; ++i) {
 
757
        int list = listBase + i;
 
758
        GLfloat x0, y0, dx, dy;
 
759
 
 
760
        FT_Error err;
 
761
 
 
762
        err = FT_Load_Glyph(face, FT_Get_Char_Index(face, i), FT_LOAD_DEFAULT);
 
763
        if (err) {
 
764
            qDebug("failed loading glyph %d from font", i);
 
765
            Q_ASSERT(!err);
 
766
        }
 
767
        err = FT_Render_Glyph(face->glyph, (antialiased ? ft_render_mode_normal
 
768
                                            : ft_render_mode_mono));
 
769
        if (err) {
 
770
            qDebug("failed rendering glyph %d from font", i);
 
771
            Q_ASSERT(!err);
 
772
        }
 
773
 
 
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;
 
778
        dy = 0;
 
779
        int sz = bm.pitch * bm.rows;
 
780
        uint *aa_glyph = 0;
 
781
        uchar *ua_glyph = 0;
 
782
 
 
783
        if (antialiased)
 
784
            aa_glyph = new uint[sz];
 
785
        else
 
786
            ua_glyph = new uchar[sz];
 
787
 
 
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;
 
793
                if (antialiased) {
 
794
                    aa_glyph[c1] = (int(color[0]*255) << 24)
 
795
                                   | (int(color[1]*255) << 16)
 
796
                                   | (int(color[2]*255) << 8) | bm.buffer[c2];
 
797
                } else {
 
798
                    ua_glyph[c1] = bm.buffer[c2];
 
799
                }
 
800
            }
 
801
        }
 
802
 
 
803
        glNewList(list, GL_COMPILE);
 
804
        if (antialiased) {
 
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);
 
810
        } else {
 
811
            glBitmap(bm.pitch*8, bm.rows, -x0, y0, dx, dy, ua_glyph);
 
812
        }
 
813
        glEndList();
 
814
        antialiased ? delete[] aa_glyph : delete[] ua_glyph;
 
815
    }
 
816
 
 
817
    engine->unlockFace();
 
818
 
 
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);
 
826
}
 
827
#endif
 
828
 
 
829
#undef d
 
830
void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
 
831
{
 
832
    QFont f(fnt);
 
833
    QFontEngine *engine = f.d->engineForScript(QUnicodeTables::Common);
 
834
 
 
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);
 
840
        return;
 
841
    }
 
842
#endif
 
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);
 
848
}
 
849
 
 
850
/*!
 
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
 
853
    obtained.
 
854
*/
 
855
void *QGLContext::getProcAddress(const QString &proc) const
 
856
{
 
857
    typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *);
 
858
    static qt_glXGetProcAddressARB glXGetProcAddressARB = 0;
 
859
 
 
860
    if (!glXGetProcAddressARB) {
 
861
        QString glxExt(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
 
862
        if (glxExt.contains("GLX_ARB_get_proc_address")) {
 
863
            QLibrary lib("GL");
 
864
            glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB");
 
865
            if (!glXGetProcAddressARB)
 
866
                return 0;
 
867
        }
 
868
    }
 
869
    return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(proc.toLatin1().data()));
 
870
}
 
871
 
 
872
/*****************************************************************************
 
873
  QGLOverlayWidget (Internal overlay class for X11)
 
874
 *****************************************************************************/
 
875
 
 
876
class QGLOverlayWidget : public QGLWidget
 
877
{
 
878
    Q_OBJECT
 
879
public:
 
880
    QGLOverlayWidget(const QGLFormat& format, QGLWidget* parent, const QGLWidget* shareWidget=0);
 
881
 
 
882
protected:
 
883
    void                initializeGL();
 
884
    void                paintGL();
 
885
    void                resizeGL(int w, int h);
 
886
 
 
887
private:
 
888
    QGLWidget*                realWidget;
 
889
 
 
890
private:
 
891
    Q_DISABLE_COPY(QGLOverlayWidget)
 
892
};
 
893
 
 
894
 
 
895
QGLOverlayWidget::QGLOverlayWidget(const QGLFormat& format, QGLWidget* parent,
 
896
                                   const QGLWidget* shareWidget)
 
897
    : QGLWidget(format, parent, shareWidget ? shareWidget->d_func()->olw : 0)
 
898
{
 
899
    realWidget = parent;
 
900
}
 
901
 
 
902
 
 
903
 
 
904
void QGLOverlayWidget::initializeGL()
 
905
{
 
906
    QColor transparentColor = context()->overlayTransparentColor();
 
907
    if (transparentColor.isValid())
 
908
        qglClearColor(transparentColor);
 
909
    else
 
910
        qWarning("QGLOverlayWidget::initializeGL(): Could not get transparent color");
 
911
    realWidget->initializeOverlayGL();
 
912
}
 
913
 
 
914
 
 
915
void QGLOverlayWidget::resizeGL(int w, int h)
 
916
{
 
917
    glViewport(0, 0, w, h);
 
918
    realWidget->resizeOverlayGL(w, h);
 
919
}
 
920
 
 
921
 
 
922
void QGLOverlayWidget::paintGL()
 
923
{
 
924
    realWidget->paintOverlayGL();
 
925
}
 
926
 
 
927
#undef Bool
 
928
#include "qgl_x11.moc"
 
929
 
 
930
/*****************************************************************************
 
931
  QGLWidget UNIX/GLX-specific code
 
932
 *****************************************************************************/
 
933
void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget *shareWidget)
 
934
{
 
935
    Q_Q(QGLWidget);
 
936
    QGLExtensions::init();
 
937
    glcx = 0;
 
938
    olw = 0;
 
939
    autoSwap = true;
 
940
    if (!context->device())
 
941
        context->setDevice(q);
 
942
 
 
943
    if (shareWidget)
 
944
        q->setContext(context, shareWidget->context());
 
945
    else
 
946
        q->setContext(context);
 
947
    q->setAttribute(Qt::WA_NoSystemBackground, true);
 
948
 
 
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);
 
957
        }
 
958
        else {
 
959
            delete olw;
 
960
            olw = 0;
 
961
            glcx->d_func()->glFormat.setOverlay(false);
 
962
        }
 
963
    }
 
964
}
 
965
 
 
966
bool QGLWidgetPrivate::renderCxPm(QPixmap* pm)
 
967
{
 
968
    Q_Q(QGLWidget);
 
969
    if (((XVisualInfo*)glcx->d_func()->vi)->depth != pm->depth())
 
970
        return false;
 
971
 
 
972
    GLXPixmap glPm;
 
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));
 
979
#else
 
980
    glPm = (quint32)glXCreateGLXPixmap(X11->display,
 
981
                                         (XVisualInfo*)glcx->d_func()->vi,
 
982
                                         (Pixmap)pm->handle());
 
983
#endif
 
984
 
 
985
    if (!glXMakeCurrent(X11->display, glPm, (GLXContext)glcx->d_func()->cx)) {
 
986
        glXDestroyGLXPixmap(X11->display, glPm);
 
987
        return false;
 
988
    }
 
989
 
 
990
    glDrawBuffer(GL_FRONT);
 
991
    if (!glcx->initialized())
 
992
        q->glInit();
 
993
    q->resizeGL(pm->width(), pm->height());
 
994
    q->paintGL();
 
995
    glFlush();
 
996
    q->makeCurrent();
 
997
    glXDestroyGLXPixmap(X11->display, glPm);
 
998
    q->resizeGL(q->width(), q->height());
 
999
    return true;
 
1000
}
 
1001
 
 
1002
/*! \internal
 
1003
  Free up any allocated colormaps. This fn is only called for
 
1004
  top-level widgets.
 
1005
*/
 
1006
void QGLWidgetPrivate::cleanupColormaps()
 
1007
{
 
1008
    if (!cmap.handle()) {
 
1009
        return;
 
1010
    } else {
 
1011
        XFreeColormap(X11->display, (Colormap) cmap.handle());
 
1012
        cmap.setHandle(0);
 
1013
    }
 
1014
}
 
1015
 
 
1016
/*! \reimp */
 
1017
bool QGLWidget::event(QEvent *e)
 
1018
{
 
1019
    return QWidget::event(e);
 
1020
}
 
1021
 
 
1022
 
 
1023
void QGLWidget::setMouseTracking(bool enable)
 
1024
{
 
1025
    Q_D(QGLWidget);
 
1026
    if (d->olw)
 
1027
        d->olw->setMouseTracking(enable);
 
1028
    QWidget::setMouseTracking(enable);
 
1029
}
 
1030
 
 
1031
 
 
1032
void QGLWidget::resizeEvent(QResizeEvent *)
 
1033
{
 
1034
    Q_D(QGLWidget);
 
1035
    if (!isValid())
 
1036
        return;
 
1037
    makeCurrent();
 
1038
    if (!d->glcx->initialized())
 
1039
        glInit();
 
1040
    glXWaitX();
 
1041
    resizeGL(width(), height());
 
1042
    if (d->olw)
 
1043
        d->olw->setGeometry(rect());
 
1044
}
 
1045
 
 
1046
const QGLContext* QGLWidget::overlayContext() const
 
1047
{
 
1048
    Q_D(const QGLWidget);
 
1049
    if (d->olw)
 
1050
        return d->olw->context();
 
1051
    else
 
1052
        return 0;
 
1053
}
 
1054
 
 
1055
 
 
1056
void QGLWidget::makeOverlayCurrent()
 
1057
{
 
1058
    Q_D(QGLWidget);
 
1059
    if (d->olw)
 
1060
        d->olw->makeCurrent();
 
1061
}
 
1062
 
 
1063
 
 
1064
void QGLWidget::updateOverlayGL()
 
1065
{
 
1066
    Q_D(QGLWidget);
 
1067
    if (d->olw)
 
1068
        d->olw->updateGL();
 
1069
}
 
1070
 
 
1071
/*!
 
1072
    \internal
 
1073
 
 
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.
 
1077
*/
 
1078
void QGLWidget::setContext(QGLContext *context,
 
1079
                            const QGLContext* shareContext,
 
1080
                            bool deleteOldContext)
 
1081
{
 
1082
    Q_D(QGLWidget);
 
1083
    if (context == 0) {
 
1084
        qWarning("QGLWidget::setContext: Cannot set null context");
 
1085
        return;
 
1086
    }
 
1087
    if (!context->deviceIsPixmap() && context->device() != this) {
 
1088
        qWarning("QGLWidget::setContext: Context must refer to this widget");
 
1089
        return;
 
1090
    }
 
1091
 
 
1092
    if (d->glcx)
 
1093
        d->glcx->doneCurrent();
 
1094
    QGLContext* oldcx = d->glcx;
 
1095
    d->glcx = context;
 
1096
 
 
1097
    bool createFailed = false;
 
1098
    if (!d->glcx->isValid()) {
 
1099
        if (!d->glcx->create(shareContext ? shareContext : oldcx))
 
1100
            createFailed = true;
 
1101
    }
 
1102
    if (createFailed) {
 
1103
        if (deleteOldContext)
 
1104
            delete oldcx;
 
1105
        return;
 
1106
    }
 
1107
 
 
1108
    if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
 
1109
        if (deleteOldContext)
 
1110
            delete oldcx;
 
1111
        return;
 
1112
    }
 
1113
 
 
1114
    bool visible = isVisible();
 
1115
    if (visible)
 
1116
        hide();
 
1117
 
 
1118
    XVisualInfo *vi = (XVisualInfo*)d->glcx->d_func()->vi;
 
1119
    XSetWindowAttributes a;
 
1120
 
 
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);
 
1126
    if (parentWidget())
 
1127
        p = parentWidget()->winId();
 
1128
 
 
1129
    Window w = XCreateWindow(X11->display, p, x(), y(), width(), height(),
 
1130
                              0, vi->depth, InputOutput, vi->visual,
 
1131
                              CWBackPixel|CWBorderPixel|CWColormap, &a);
 
1132
 
 
1133
    Window *cmw;
 
1134
    Window *cmwret;
 
1135
    int count;
 
1136
    if (XGetWMColormapWindows(X11->display, window()->winId(),
 
1137
                                &cmwret, &count)) {
 
1138
        cmw = new Window[count+1];
 
1139
        memcpy((char *)cmw, (char *)cmwret, sizeof(Window)*count);
 
1140
        XFree((char *)cmwret);
 
1141
        int i;
 
1142
        for (i=0; i<count; i++) {
 
1143
            if (cmw[i] == winId()) {                // replace old window
 
1144
                cmw[i] = w;
 
1145
                break;
 
1146
            }
 
1147
        }
 
1148
        if (i >= count)                        // append new window
 
1149
            cmw[count++] = w;
 
1150
    } else {
 
1151
        count = 1;
 
1152
        cmw = new Window[count];
 
1153
        cmw[0] = w;
 
1154
    }
 
1155
 
 
1156
#if defined(GLX_MESA_release_buffers) && defined(QGL_USE_MESA_EXT)
 
1157
    if (oldcx && oldcx->windowCreated())
 
1158
        glXReleaseBuffersMESA(X11->display, winId());
 
1159
#endif
 
1160
    if (deleteOldContext)
 
1161
        delete oldcx;
 
1162
    oldcx = 0;
 
1163
 
 
1164
    create(w);
 
1165
 
 
1166
    XSetWMColormapWindows(X11->display, window()->winId(), cmw,
 
1167
                           count);
 
1168
    delete [] cmw;
 
1169
 
 
1170
    // calling QWidget::create() will always result in a new paint
 
1171
    // engine being created - get rid of it and replace it with our
 
1172
    // own
 
1173
 
 
1174
    if (visible)
 
1175
        show();
 
1176
    XFlush(X11->display);
 
1177
    d->glcx->setWindowCreated(true);
 
1178
}
 
1179
 
 
1180
const QGLColormap & QGLWidget::colormap() const
 
1181
{
 
1182
    Q_D(const QGLWidget);
 
1183
    return d->cmap;
 
1184
}
 
1185
 
 
1186
/*\internal
 
1187
  Store color values in the given colormap.
 
1188
*/
 
1189
static void qStoreColors(QWidget * tlw, Colormap cmap,
 
1190
                          const QGLColormap & cols)
 
1191
{
 
1192
    Q_UNUSED(tlw);
 
1193
    XColor c;
 
1194
    QRgb color;
 
1195
 
 
1196
    for (int i = 0; i < cols.size(); i++) {
 
1197
        color = cols.entryRgb(i);
 
1198
        c.pixel = 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);
 
1204
    }
 
1205
}
 
1206
 
 
1207
/*\internal
 
1208
  Check whether the given visual supports dynamic colormaps or not.
 
1209
*/
 
1210
static bool qCanAllocColors(QWidget * w)
 
1211
{
 
1212
    bool validVisual = false;
 
1213
    int  numVisuals;
 
1214
    long mask;
 
1215
    XVisualInfo templ;
 
1216
    XVisualInfo * visuals;
 
1217
    VisualID id = XVisualIDFromVisual((Visual *) w->window()->x11Info().visual());
 
1218
 
 
1219
    mask = VisualScreenMask;
 
1220
    templ.screen = w->x11Info().screen();
 
1221
    visuals = XGetVisualInfo(X11->display, mask, &templ, &numVisuals);
 
1222
 
 
1223
    for (int i = 0; i < numVisuals; i++) {
 
1224
        if (visuals[i].visualid == id) {
 
1225
            switch (visuals[i].c_class) {
 
1226
                case TrueColor:
 
1227
                case StaticColor:
 
1228
                case StaticGray:
 
1229
                case XGrayScale:
 
1230
                    validVisual = false;
 
1231
                    break;
 
1232
                case DirectColor:
 
1233
                case PseudoColor:
 
1234
                    validVisual = true;
 
1235
                    break;
 
1236
            }
 
1237
            break;
 
1238
        }
 
1239
    }
 
1240
    XFree(visuals);
 
1241
 
 
1242
    if (!validVisual)
 
1243
        return false;
 
1244
    return true;
 
1245
}
 
1246
 
 
1247
 
 
1248
void QGLWidget::setColormap(const QGLColormap & c)
 
1249
{
 
1250
    Q_D(QGLWidget);
 
1251
    QWidget * tlw = window(); // must return a valid widget
 
1252
 
 
1253
    d->cmap = c;
 
1254
    if (!d->cmap.handle())
 
1255
        return;
 
1256
 
 
1257
    if (!qCanAllocColors(this)) {
 
1258
        qWarning("QGLWidget::setColormap: Cannot create a read/write "
 
1259
                  "colormap for this visual");
 
1260
        return;
 
1261
    }
 
1262
 
 
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());
 
1269
    if (cvId != tvId) {
 
1270
        wid = winId();
 
1271
        vis = (Visual *) x11Info().visual();
 
1272
    }
 
1273
 
 
1274
    if (!d->cmap.handle()) // allocate a cmap if necessary
 
1275
        d->cmap.setHandle(XCreateColormap(X11->display, wid, vis, AllocAll));
 
1276
 
 
1277
    qStoreColors(this, (Colormap) d->cmap.handle(), c);
 
1278
    XSetWindowColormap(X11->display, wid, (Colormap) d->cmap.handle());
 
1279
 
 
1280
    // tell the wm that this window has a special colormap
 
1281
    Window * cmw;
 
1282
    Window * cmwret;
 
1283
    int count;
 
1284
    if (XGetWMColormapWindows(X11->display, tlw->winId(), &cmwret, &count))
 
1285
    {
 
1286
        cmw = new Window[count+1];
 
1287
        memcpy((char *) cmw, (char *) cmwret, sizeof(Window) * count);
 
1288
        XFree((char *) cmwret);
 
1289
        int i;
 
1290
        for (i = 0; i < count; i++) {
 
1291
            if (cmw[i] == winId()) {
 
1292
                break;
 
1293
            }
 
1294
        }
 
1295
        if (i >= count)   // append new window only if not in the list
 
1296
            cmw[count++] = winId();
 
1297
    } else {
 
1298
        count = 1;
 
1299
        cmw = new Window[count];
 
1300
        cmw[0] = winId();
 
1301
    }
 
1302
    XSetWMColormapWindows(X11->display, tlw->winId(), cmw, count);
 
1303
    delete [] cmw;
 
1304
}
 
1305
 
 
1306
void QGLExtensions::init()
 
1307
{
 
1308
    static bool init_done = false;
 
1309
 
 
1310
    if (init_done)
 
1311
        return;
 
1312
    init_done = true;
 
1313
 
 
1314
    Window win;
 
1315
    int attribs[] = { GLX_RGBA, XNone };
 
1316
    int attribs_dbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, XNone };
 
1317
 
 
1318
    XSetWindowAttributes attr;
 
1319
    unsigned long mask;
 
1320
    Window root;
 
1321
    GLXContext ctx;
 
1322
    XVisualInfo *visinfo;
 
1323
    int width = 10, height = 10;
 
1324
 
 
1325
    root = RootWindow(X11->display, 0);
 
1326
 
 
1327
    visinfo = glXChooseVisual(X11->display, 0, attribs);
 
1328
    if (!visinfo) {
 
1329
        visinfo = glXChooseVisual(X11->display, 0, attribs_dbl);
 
1330
        if (!visinfo) {
 
1331
            qDebug("QGLExtensions: couldn't find any RGB visuals.");
 
1332
            return;
 
1333
        }
 
1334
    }
 
1335
 
 
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);
 
1343
 
 
1344
    ctx = glXCreateContext(X11->display, visinfo, NULL, true);
 
1345
 
 
1346
    if (visinfo)
 
1347
        XFree(visinfo);
 
1348
 
 
1349
    if (ctx) {
 
1350
        if (glXMakeCurrent(X11->display, win, ctx))
 
1351
            init_extensions();
 
1352
        else
 
1353
            qDebug("QGLExtensions: glXMakeCurrent() failed.");
 
1354
        glXDestroyContext(X11->display, ctx);
 
1355
    } else {
 
1356
        qDebug("QGLExtensions: glXCreateContext failed.");
 
1357
    }
 
1358
    XDestroyWindow(X11->display, win);
 
1359
    XFreeColormap(X11->display, attr.colormap);
 
1360
}