source: trunk/src/opengl/qgl_x11.cpp@ 158

Last change on this file since 158 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 45.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtOpenGL module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qgl.h"
43#include "qgl_p.h"
44
45#include "qmap.h"
46#include "qapplication.h"
47#include "qcolormap.h"
48#include "qdesktopwidget.h"
49#include "qpixmap.h"
50#include "qhash.h"
51#include "qlibrary.h"
52#include "qdebug.h"
53#include <private/qfontengine_ft_p.h>
54#include <private/qt_x11_p.h>
55#ifdef Q_OS_HPUX
56// for GLXPBuffer
57#include <private/qglpixelbuffer_p.h>
58#endif
59
60#define INT8 dummy_INT8
61#define INT32 dummy_INT32
62#include <GL/glx.h>
63#undef INT8
64#undef INT32
65#include <X11/Xlib.h>
66#include <X11/Xutil.h>
67#include <X11/Xos.h>
68#include <X11/Xatom.h>
69
70#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
71#include <dlfcn.h>
72#endif
73
74QT_BEGIN_NAMESPACE
75
76extern Drawable qt_x11Handle(const QPaintDevice *pd);
77extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
78
79#ifndef GLX_ARB_multisample
80#define GLX_SAMPLE_BUFFERS_ARB 100000
81#define GLX_SAMPLES_ARB 100001
82#endif
83
84/*
85 The qt_gl_choose_cmap function is internal and used by QGLWidget::setContext()
86 and GLX (not Windows). If the application can't find any sharable
87 colormaps, it must at least create as few colormaps as possible. The
88 dictionary solution below ensures only one colormap is created per visual.
89 Colormaps are also deleted when the application terminates.
90*/
91
92struct QCMapEntry {
93 QCMapEntry();
94 ~QCMapEntry();
95
96 Colormap cmap;
97 bool alloc;
98 XStandardColormap scmap;
99};
100
101QCMapEntry::QCMapEntry()
102{
103 cmap = 0;
104 alloc = false;
105 scmap.colormap = 0;
106}
107
108QCMapEntry::~QCMapEntry()
109{
110 if (alloc)
111 XFreeColormap(X11->display, cmap);
112}
113typedef QHash<int, QCMapEntry *> CMapEntryHash;
114typedef QHash<int, QMap<int, QRgb> > GLCMapHash;
115static bool mesa_gl = false;
116static bool first_time = true;
117
118static void cleanup_cmaps();
119
120struct QGLCMapCleanupHandler {
121 QGLCMapCleanupHandler() {
122 cmap_hash = new CMapEntryHash;
123 qglcmap_hash = new GLCMapHash;
124 }
125 ~QGLCMapCleanupHandler() {
126 delete cmap_hash;
127 delete qglcmap_hash;
128 }
129 CMapEntryHash *cmap_hash;
130 GLCMapHash *qglcmap_hash;
131};
132Q_GLOBAL_STATIC(QGLCMapCleanupHandler, cmap_handler);
133
134static void cleanup_cmaps()
135{
136 CMapEntryHash *hash = cmap_handler()->cmap_hash;
137 QHash<int, QCMapEntry *>::ConstIterator it = hash->constBegin();
138 while (it != hash->constEnd()) {
139 delete it.value();
140 ++it;
141 }
142
143 hash->clear();
144 cmap_handler()->qglcmap_hash->clear();
145}
146
147Colormap qt_gl_choose_cmap(Display *dpy, XVisualInfo *vi)
148{
149 if (first_time) {
150 const char *v = glXQueryServerString(dpy, vi->screen, GLX_VERSION);
151 if (v)
152 mesa_gl = (strstr(v, "Mesa") != 0);
153 first_time = false;
154 }
155
156 CMapEntryHash *hash = cmap_handler()->cmap_hash;
157 CMapEntryHash::ConstIterator it = hash->constFind((long) vi->visualid + (vi->screen * 256));
158 if (it != hash->constEnd())
159 return it.value()->cmap; // found colormap for visual
160
161 if (vi->visualid ==
162 XVisualIDFromVisual((Visual *) QX11Info::appVisual(vi->screen))) {
163 // qDebug("Using x11AppColormap");
164 return QX11Info::appColormap(vi->screen);
165 }
166
167 QCMapEntry *x = new QCMapEntry();
168
169 XStandardColormap *c;
170 int n, i;
171
172 // qDebug("Choosing cmap for vID %0x", vi->visualid);
173
174 if (mesa_gl) { // we're using MesaGL
175 Atom hp_cmaps = XInternAtom(dpy, "_HP_RGB_SMOOTH_MAP_LIST", true);
176 if (hp_cmaps && vi->visual->c_class == TrueColor && vi->depth == 8) {
177 if (XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n,
178 hp_cmaps)) {
179 i = 0;
180 while (i < n && x->cmap == 0) {
181 if (c[i].visualid == vi->visual->visualid) {
182 x->cmap = c[i].colormap;
183 x->scmap = c[i];
184 //qDebug("Using HP_RGB scmap");
185
186 }
187 i++;
188 }
189 XFree((char *)c);
190 }
191 }
192 }
193 if (!x->cmap) {
194 if (XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n,
195 XA_RGB_DEFAULT_MAP)) {
196 for (int i = 0; i < n && x->cmap == 0; ++i) {
197 if (!c[i].red_max ||
198 !c[i].green_max ||
199 !c[i].blue_max ||
200 !c[i].red_mult ||
201 !c[i].green_mult ||
202 !c[i].blue_mult)
203 continue; // invalid stdcmap
204 if (c[i].visualid == vi->visualid) {
205 x->cmap = c[i].colormap;
206 x->scmap = c[i];
207 //qDebug("Using RGB_DEFAULT scmap");
208 }
209 }
210 XFree((char *)c);
211 }
212 }
213 if (!x->cmap) { // no shared cmap found
214 x->cmap = XCreateColormap(dpy, RootWindow(dpy,vi->screen), vi->visual,
215 AllocNone);
216 x->alloc = true;
217 // qDebug("Allocating cmap");
218 }
219
220 // colormap hash should be cleanup only when the QApplication dtor is called
221 if (hash->isEmpty())
222 qAddPostRoutine(cleanup_cmaps);
223
224 // associate cmap with visualid
225 hash->insert((long) vi->visualid + (vi->screen * 256), x);
226 return x->cmap;
227}
228
229struct QTransColor
230{
231 VisualID vis;
232 int screen;
233 long color;
234};
235
236static QVector<QTransColor> trans_colors;
237static int trans_colors_init = false;
238
239static void find_trans_colors()
240{
241 struct OverlayProp {
242 long visual;
243 long type;
244 long value;
245 long layer;
246 };
247
248 trans_colors_init = true;
249
250 Display* appDisplay = X11->display;
251
252 int scr;
253 int lastsize = 0;
254 for (scr = 0; scr < ScreenCount(appDisplay); scr++) {
255 QWidget* rootWin = QApplication::desktop()->screen(scr);
256 if (!rootWin)
257 return; // Should not happen
258 Atom overlayVisualsAtom = XInternAtom(appDisplay,
259 "SERVER_OVERLAY_VISUALS", True);
260 if (overlayVisualsAtom == XNone)
261 return; // Server has no overlays
262
263 Atom actualType;
264 int actualFormat;
265 ulong nItems;
266 ulong bytesAfter;
267 unsigned char *retval = 0;
268 int res = XGetWindowProperty(appDisplay, rootWin->winId(),
269 overlayVisualsAtom, 0, 10000, False,
270 overlayVisualsAtom, &actualType,
271 &actualFormat, &nItems, &bytesAfter,
272 &retval);
273
274 if (res != Success || actualType != overlayVisualsAtom
275 || actualFormat != 32 || nItems < 4 || !retval)
276 return; // Error reading property
277
278 OverlayProp *overlayProps = (OverlayProp *)retval;
279
280 int numProps = nItems / 4;
281 trans_colors.resize(lastsize + numProps);
282 int j = lastsize;
283 for (int i = 0; i < numProps; i++) {
284 if (overlayProps[i].type == 1) {
285 trans_colors[j].vis = (VisualID)overlayProps[i].visual;
286 trans_colors[j].screen = scr;
287 trans_colors[j].color = (int)overlayProps[i].value;
288 j++;
289 }
290 }
291 XFree(overlayProps);
292 lastsize = j;
293 trans_colors.resize(lastsize);
294 }
295}
296
297/*****************************************************************************
298 QGLFormat UNIX/GLX-specific code
299 *****************************************************************************/
300
301bool QGLFormat::hasOpenGL()
302{
303 return glXQueryExtension(X11->display, 0, 0) != 0;
304}
305
306
307bool QGLFormat::hasOpenGLOverlays()
308{
309 if (!trans_colors_init)
310 find_trans_colors();
311 return trans_colors.size() > 0;
312}
313
314/*****************************************************************************
315 QGLContext UNIX/GLX-specific code
316 *****************************************************************************/
317
318bool QGLContext::chooseContext(const QGLContext* shareContext)
319{
320 Q_D(QGLContext);
321 const QX11Info *xinfo = qt_x11Info(d->paintDevice);
322
323 Display* disp = xinfo->display();
324 d->vi = chooseVisual();
325 if (!d->vi)
326 return false;
327
328 if (deviceIsPixmap() &&
329 (((XVisualInfo*)d->vi)->depth != xinfo->depth() ||
330 ((XVisualInfo*)d->vi)->screen != xinfo->screen()))
331 {
332 XFree(d->vi);
333 XVisualInfo appVisInfo;
334 memset(&appVisInfo, 0, sizeof(XVisualInfo));
335 appVisInfo.visualid = XVisualIDFromVisual((Visual *) xinfo->visual());
336 appVisInfo.screen = xinfo->screen();
337 int nvis;
338 d->vi = XGetVisualInfo(disp, VisualIDMask | VisualScreenMask, &appVisInfo, &nvis);
339 if (!d->vi)
340 return false;
341
342 int useGL;
343 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_USE_GL, &useGL);
344 if (!useGL)
345 return false; //# Chickening out already...
346 }
347 int res;
348 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_LEVEL, &res);
349 d->glFormat.setPlane(res);
350 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_DOUBLEBUFFER, &res);
351 d->glFormat.setDoubleBuffer(res);
352 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_DEPTH_SIZE, &res);
353 d->glFormat.setDepth(res);
354 if (d->glFormat.depth())
355 d->glFormat.setDepthBufferSize(res);
356 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_RGBA, &res);
357 d->glFormat.setRgba(res);
358 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_RED_SIZE, &res);
359 d->glFormat.setRedBufferSize(res);
360 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_GREEN_SIZE, &res);
361 d->glFormat.setGreenBufferSize(res);
362 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_BLUE_SIZE, &res);
363 d->glFormat.setBlueBufferSize(res);
364 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_ALPHA_SIZE, &res);
365 d->glFormat.setAlpha(res);
366 if (d->glFormat.alpha())
367 d->glFormat.setAlphaBufferSize(res);
368 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_ACCUM_RED_SIZE, &res);
369 d->glFormat.setAccum(res);
370 if (d->glFormat.accum())
371 d->glFormat.setAccumBufferSize(res);
372 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_STENCIL_SIZE, &res);
373 d->glFormat.setStencil(res);
374 if (d->glFormat.stencil())
375 d->glFormat.setStencilBufferSize(res);
376 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_STEREO, &res);
377 d->glFormat.setStereo(res);
378 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_SAMPLE_BUFFERS_ARB, &res);
379 d->glFormat.setSampleBuffers(res);
380 if (d->glFormat.sampleBuffers()) {
381 glXGetConfig(disp, (XVisualInfo*)d->vi, GLX_SAMPLES_ARB, &res);
382 d->glFormat.setSamples(res);
383 }
384
385 Bool direct = format().directRendering() ? True : False;
386
387 if (shareContext &&
388 (!shareContext->isValid() || !shareContext->d_func()->cx)) {
389 qWarning("QGLContext::chooseContext(): Cannot share with invalid context");
390 shareContext = 0;
391 }
392
393 // 1. Sharing between rgba and color-index will give wrong colors.
394 // 2. Contexts cannot be shared btw. direct/non-direct renderers.
395 // 3. Pixmaps cannot share contexts that are set up for direct rendering.
396 // 4. If the contexts are not created on the same screen, they can't be shared
397
398 if (shareContext
399 && (format().rgba() != shareContext->format().rgba()
400 || (deviceIsPixmap() && glXIsDirect(disp, (GLXContext)shareContext->d_func()->cx))
401 || (shareContext->d_func()->screen != xinfo->screen())))
402 {
403 shareContext = 0;
404 }
405
406 d->cx = 0;
407 if (shareContext) {
408 d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi,
409 (GLXContext)shareContext->d_func()->cx, direct);
410 d->screen = ((XVisualInfo*)d->vi)->screen;
411 if (d->cx) {
412 QGLContext *share = const_cast<QGLContext *>(shareContext);
413 d->sharing = true;
414 share->d_func()->sharing = true;
415 }
416 }
417 if (!d->cx) {
418 d->cx = glXCreateContext(disp, (XVisualInfo *)d->vi, NULL, direct);
419 d->screen = ((XVisualInfo*)d->vi)->screen;
420 }
421 if (!d->cx)
422 return false;
423 d->glFormat.setDirectRendering(glXIsDirect(disp, (GLXContext)d->cx));
424 if (deviceIsPixmap()) {
425#if defined(GLX_MESA_pixmap_colormap) && defined(QGL_USE_MESA_EXT)
426 d->gpm = glXCreateGLXPixmapMESA(disp, (XVisualInfo *)d->vi,
427 qt_x11Handle(d->paintDevice),
428 qt_gl_choose_cmap(disp, (XVisualInfo *)d->vi));
429#else
430 d->gpm = (quint32)glXCreateGLXPixmap(disp, (XVisualInfo *)d->vi,
431 qt_x11Handle(d->paintDevice));
432#endif
433 if (!d->gpm)
434 return false;
435 }
436 QString glxExt = QString(QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)));
437 if (glxExt.contains(QLatin1String("GLX_SGI_video_sync"))) {
438 if (d->glFormat.swapInterval() == -1)
439 d->glFormat.setSwapInterval(0);
440 } else {
441 d->glFormat.setSwapInterval(-1);
442 }
443 return true;
444}
445
446
447/*!
448 \bold{X11 only:} This virtual function tries to find a
449 visual that matches the format, reducing the demands if the original
450 request cannot be met.
451
452 The algorithm for reducing the demands of the format is quite
453 simple-minded, so override this method in your subclass if your
454 application has spcific requirements on visual selection.
455
456 \sa chooseContext()
457*/
458
459void *QGLContext::chooseVisual()
460{
461 Q_D(QGLContext);
462 static const int bufDepths[] = { 8, 4, 2, 1 }; // Try 16, 12 also?
463 //todo: if pixmap, also make sure that vi->depth == pixmap->depth
464 void* vis = 0;
465 int i = 0;
466 bool fail = false;
467 QGLFormat fmt = format();
468 bool tryDouble = !fmt.doubleBuffer(); // Some GL impl's only have double
469 bool triedDouble = false;
470 bool triedSample = false;
471 if (fmt.sampleBuffers())
472 fmt.setSampleBuffers(QGLExtensions::glExtensions & QGLExtensions::SampleBuffers);
473 while(!fail && !(vis = tryVisual(fmt, bufDepths[i]))) {
474 if (!fmt.rgba() && bufDepths[i] > 1) {
475 i++;
476 continue;
477 }
478 if (tryDouble) {
479 fmt.setDoubleBuffer(true);
480 tryDouble = false;
481 triedDouble = true;
482 continue;
483 } else if (triedDouble) {
484 fmt.setDoubleBuffer(false);
485 triedDouble = false;
486 }
487 if (!triedSample && fmt.sampleBuffers()) {
488 fmt.setSampleBuffers(false);
489 triedSample = true;
490 continue;
491 }
492 if (fmt.stereo()) {
493 fmt.setStereo(false);
494 continue;
495 }
496 if (fmt.accum()) {
497 fmt.setAccum(false);
498 continue;
499 }
500 if (fmt.stencil()) {
501 fmt.setStencil(false);
502 continue;
503 }
504 if (fmt.alpha()) {
505 fmt.setAlpha(false);
506 continue;
507 }
508 if (fmt.depth()) {
509 fmt.setDepth(false);
510 continue;
511 }
512 if (fmt.doubleBuffer()) {
513 fmt.setDoubleBuffer(false);
514 continue;
515 }
516 fail = true;
517 }
518 d->glFormat = fmt;
519 return vis;
520}
521
522
523/*!
524 \internal
525
526 \bold{X11 only:} This virtual function chooses a visual
527 that matches the OpenGL \link format() format\endlink. Reimplement this
528 function in a subclass if you need a custom visual.
529
530 \sa chooseContext()
531*/
532
533void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth)
534{
535 Q_D(QGLContext);
536 int spec[40];
537 int i = 0;
538 spec[i++] = GLX_LEVEL;
539 spec[i++] = f.plane();
540 const QX11Info *xinfo = qt_x11Info(d->paintDevice);
541
542#if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
543 static bool useTranspExt = false;
544 static bool useTranspExtChecked = false;
545 if (f.plane() && !useTranspExtChecked && d->paintDevice) {
546 QByteArray estr(glXQueryExtensionsString(xinfo->display(), xinfo->screen()));
547 useTranspExt = estr.contains("GLX_EXT_visual_info");
548 //# (A bit simplistic; that could theoretically be a substring)
549 if (useTranspExt) {
550 QByteArray cstr(glXGetClientString(xinfo->display(), GLX_VENDOR));
551 useTranspExt = !cstr.contains("Xi Graphics"); // bug workaround
552 if (useTranspExt) {
553 // bug workaround - some systems (eg. FireGL) refuses to return an overlay
554 // visual if the GLX_TRANSPARENT_TYPE_EXT attribute is specified, even if
555 // the implementation supports transparent overlays
556 int tmpSpec[] = { GLX_LEVEL, f.plane(), GLX_TRANSPARENT_TYPE_EXT,
557 f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT,
558 XNone };
559 XVisualInfo * vinf = glXChooseVisual(xinfo->display(), xinfo->screen(), tmpSpec);
560 if (!vinf) {
561 useTranspExt = false;
562 }
563 }
564 }
565
566 useTranspExtChecked = true;
567 }
568 if (f.plane() && useTranspExt) {
569 // Required to avoid non-transparent overlay visual(!) on some systems
570 spec[i++] = GLX_TRANSPARENT_TYPE_EXT;
571 spec[i++] = f.rgba() ? GLX_TRANSPARENT_RGB_EXT : GLX_TRANSPARENT_INDEX_EXT;
572 }
573#endif
574
575 if (f.doubleBuffer())
576 spec[i++] = GLX_DOUBLEBUFFER;
577 if (f.depth()) {
578 spec[i++] = GLX_DEPTH_SIZE;
579 spec[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize();
580 }
581 if (f.stereo()) {
582 spec[i++] = GLX_STEREO;
583 }
584 if (f.stencil()) {
585 spec[i++] = GLX_STENCIL_SIZE;
586 spec[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize();
587 }
588 if (f.rgba()) {
589 spec[i++] = GLX_RGBA;
590 spec[i++] = GLX_RED_SIZE;
591 spec[i++] = f.redBufferSize() == -1 ? 1 : f.redBufferSize();
592 spec[i++] = GLX_GREEN_SIZE;
593 spec[i++] = f.greenBufferSize() == -1 ? 1 : f.greenBufferSize();
594 spec[i++] = GLX_BLUE_SIZE;
595 spec[i++] = f.blueBufferSize() == -1 ? 1 : f.blueBufferSize();
596 if (f.alpha()) {
597 spec[i++] = GLX_ALPHA_SIZE;
598 spec[i++] = f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize();
599 }
600 if (f.accum()) {
601 spec[i++] = GLX_ACCUM_RED_SIZE;
602 spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
603 spec[i++] = GLX_ACCUM_GREEN_SIZE;
604 spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
605 spec[i++] = GLX_ACCUM_BLUE_SIZE;
606 spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
607 if (f.alpha()) {
608 spec[i++] = GLX_ACCUM_ALPHA_SIZE;
609 spec[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
610 }
611 }
612 } else {
613 spec[i++] = GLX_BUFFER_SIZE;
614 spec[i++] = bufDepth;
615 }
616
617 if (f.sampleBuffers()) {
618 spec[i++] = GLX_SAMPLE_BUFFERS_ARB;
619 spec[i++] = 1;
620 spec[i++] = GLX_SAMPLES_ARB;
621 spec[i++] = f.samples() == -1 ? 4 : f.samples();
622 }
623
624 spec[i] = XNone;
625 return glXChooseVisual(xinfo->display(), xinfo->screen(), spec);
626}
627
628
629void QGLContext::reset()
630{
631 Q_D(QGLContext);
632 if (!d->valid)
633 return;
634 d->cleanup();
635 const QX11Info *xinfo = qt_x11Info(d->paintDevice);
636 doneCurrent();
637 if (d->gpm)
638 glXDestroyGLXPixmap(xinfo->display(), (GLXPixmap)d->gpm);
639 d->gpm = 0;
640 glXDestroyContext(xinfo->display(), (GLXContext)d->cx);
641 if (d->vi)
642 XFree(d->vi);
643 d->vi = 0;
644 d->cx = 0;
645 d->crWin = false;
646 d->sharing = false;
647 d->valid = false;
648 d->transpColor = QColor();
649 d->initDone = false;
650 qgl_share_reg()->removeShare(this);
651}
652
653
654void QGLContext::makeCurrent()
655{
656 Q_D(QGLContext);
657 if (!d->valid) {
658 qWarning("QGLContext::makeCurrent(): Cannot make invalid context current.");
659 return;
660 }
661 const QX11Info *xinfo = qt_x11Info(d->paintDevice);
662 bool ok = true;
663 if (d->paintDevice->devType() == QInternal::Pixmap) {
664 ok = glXMakeCurrent(xinfo->display(), (GLXPixmap)d->gpm, (GLXContext)d->cx);
665 } else if (d->paintDevice->devType() == QInternal::Pbuffer) {
666 ok = glXMakeCurrent(xinfo->display(), (GLXPbuffer)d->pbuf, (GLXContext)d->cx);
667 } else if (d->paintDevice->devType() == QInternal::Widget) {
668 ok = glXMakeCurrent(xinfo->display(), ((QWidget *)d->paintDevice)->winId(), (GLXContext)d->cx);
669 }
670 if (!ok)
671 qWarning("QGLContext::makeCurrent(): Failed.");
672
673 if (ok) {
674 if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
675 qgl_context_storage.setLocalData(new QGLThreadContext);
676 if (qgl_context_storage.hasLocalData())
677 qgl_context_storage.localData()->context = this;
678 currentCtx = this;
679 }
680}
681
682void QGLContext::doneCurrent()
683{
684 Q_D(QGLContext);
685 glXMakeCurrent(qt_x11Info(d->paintDevice)->display(), 0, 0);
686 if (qgl_context_storage.hasLocalData())
687 qgl_context_storage.localData()->context = 0;
688 currentCtx = 0;
689}
690
691
692void QGLContext::swapBuffers() const
693{
694 Q_D(const QGLContext);
695 if (!d->valid)
696 return;
697 if (!deviceIsPixmap()) {
698 int interval = d->glFormat.swapInterval();
699 if (interval > 0) {
700 typedef int (*qt_glXGetVideoSyncSGI)(uint *);
701 typedef int (*qt_glXWaitVideoSyncSGI)(int, int, uint *);
702 static qt_glXGetVideoSyncSGI glXGetVideoSyncSGI = 0;
703 static qt_glXWaitVideoSyncSGI glXWaitVideoSyncSGI = 0;
704 static bool resolved = false;
705 if (!resolved) {
706 QString glxExt = QString(QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)));
707 if (glxExt.contains(QLatin1String("GLX_SGI_video_sync"))) {
708#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
709 void *handle = dlopen(NULL, RTLD_LAZY);
710 if (handle) {
711 glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI) dlsym(handle, "glXGetVideoSyncSGI");
712 glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI) dlsym(handle, "glXWaitVideoSyncSGI");
713 dlclose(handle);
714 }
715 if (!glXGetVideoSyncSGI)
716#endif
717 {
718 extern const QString qt_gl_library_name();
719 QLibrary lib(qt_gl_library_name());
720 glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI) lib.resolve("glXGetVideoSyncSGI");
721 glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI) lib.resolve("glXWaitVideoSyncSGI");
722 }
723 }
724 resolved = true;
725 }
726 if (glXGetVideoSyncSGI && glXWaitVideoSyncSGI) {
727 uint counter;
728 if (!glXGetVideoSyncSGI(&counter))
729 glXWaitVideoSyncSGI(interval + 1, (counter + interval) % (interval + 1), &counter);
730 }
731 }
732 glXSwapBuffers(qt_x11Info(d->paintDevice)->display(),
733 static_cast<QWidget *>(d->paintDevice)->winId());
734 }
735}
736
737QColor QGLContext::overlayTransparentColor() const
738{
739 if (isValid())
740 return Qt::transparent;
741 return QColor(); // Invalid color
742}
743
744static uint qt_transparent_pixel(VisualID id, int screen)
745{
746 for (int i = 0; i < trans_colors.size(); i++) {
747 if (trans_colors[i].vis == id && trans_colors[i].screen == screen)
748 return trans_colors[i].color;
749 }
750 return 0;
751}
752
753uint QGLContext::colorIndex(const QColor& c) const
754{
755 Q_D(const QGLContext);
756 int screen = ((XVisualInfo *)d->vi)->screen;
757 QColormap colmap = QColormap::instance(screen);
758 if (isValid()) {
759 if (format().plane() && c == Qt::transparent) {
760 return qt_transparent_pixel(((XVisualInfo *)d->vi)->visualid,
761 ((XVisualInfo *)d->vi)->screen);
762 }
763 if (((XVisualInfo*)d->vi)->visualid ==
764 XVisualIDFromVisual((Visual *) QX11Info::appVisual(screen)))
765 return colmap.pixel(c); // We're using QColor's cmap
766
767 XVisualInfo *info = (XVisualInfo *) d->vi;
768 CMapEntryHash *hash = cmap_handler()->cmap_hash;
769 CMapEntryHash::ConstIterator it = hash->constFind(long(info->visualid)
770 + (info->screen * 256));
771 QCMapEntry *x = 0;
772 if (it != hash->constEnd())
773 x = it.value();
774 if (x && !x->alloc) { // It's a standard colormap
775 int rf = (int)(((float)c.red() * (x->scmap.red_max+1))/256.0);
776 int gf = (int)(((float)c.green() * (x->scmap.green_max+1))/256.0);
777 int bf = (int)(((float)c.blue() * (x->scmap.blue_max+1))/256.0);
778 uint p = x->scmap.base_pixel
779 + (rf * x->scmap.red_mult)
780 + (gf * x->scmap.green_mult)
781 + (bf * x->scmap.blue_mult);
782 return p;
783 } else {
784 QMap<int, QRgb> &cmap = (*cmap_handler()->qglcmap_hash)[(long)info->visualid];
785
786 // already in the map?
787 QRgb target = c.rgb();
788 QMap<int, QRgb>::Iterator it = cmap.begin();
789 for (; it != cmap.end(); ++it) {
790 if ((*it) == target)
791 return it.key();
792 }
793
794 // need to alloc color
795 unsigned long plane_mask[2];
796 unsigned long color_map_entry;
797 if (!XAllocColorCells (QX11Info::display(), x->cmap, true, plane_mask, 0,
798 &color_map_entry, 1))
799 return colmap.pixel(c);
800
801 XColor col;
802 col.flags = DoRed | DoGreen | DoBlue;
803 col.pixel = color_map_entry;
804 col.red = (ushort)((qRed(c.rgb()) / 255.0) * 65535.0 + 0.5);
805 col.green = (ushort)((qGreen(c.rgb()) / 255.0) * 65535.0 + 0.5);
806 col.blue = (ushort)((qBlue(c.rgb()) / 255.0) * 65535.0 + 0.5);
807 XStoreColor(QX11Info::display(), x->cmap, &col);
808
809 cmap.insert(color_map_entry, target);
810 return color_map_entry;
811 }
812 }
813 return 0;
814}
815
816#ifndef QT_NO_FONTCONFIG
817/*! \internal
818 This is basically a substitute for glxUseXFont() which can only
819 handle XLFD fonts. This version relies on freetype to render the
820 glyphs, but it works with all fonts that fontconfig provides - both
821 antialiased and aliased bitmap and outline fonts.
822*/
823static void qgl_use_font(QFontEngineFT *engine, int first, int count, int listBase)
824{
825 GLfloat color[4];
826 glGetFloatv(GL_CURRENT_COLOR, color);
827
828 // save the pixel unpack state
829 GLint gl_swapbytes, gl_lsbfirst, gl_rowlength, gl_skiprows, gl_skippixels, gl_alignment;
830 glGetIntegerv (GL_UNPACK_SWAP_BYTES, &gl_swapbytes);
831 glGetIntegerv (GL_UNPACK_LSB_FIRST, &gl_lsbfirst);
832 glGetIntegerv (GL_UNPACK_ROW_LENGTH, &gl_rowlength);
833 glGetIntegerv (GL_UNPACK_SKIP_ROWS, &gl_skiprows);
834 glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &gl_skippixels);
835 glGetIntegerv (GL_UNPACK_ALIGNMENT, &gl_alignment);
836
837 glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
838 glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
839 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
840 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
841 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
842 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
843
844 const bool antialiased = engine->drawAntialiased();
845 FT_Face face = engine->lockFace();
846
847 // start generating font glyphs
848 for (int i = first; i < count; ++i) {
849 int list = listBase + i;
850 GLfloat x0, y0, dx, dy;
851
852 FT_Error err;
853
854 err = FT_Load_Glyph(face, FT_Get_Char_Index(face, i), FT_LOAD_DEFAULT);
855 if (err) {
856 qDebug("failed loading glyph %d from font", i);
857 Q_ASSERT(!err);
858 }
859 err = FT_Render_Glyph(face->glyph, (antialiased ? FT_RENDER_MODE_NORMAL
860 : FT_RENDER_MODE_MONO));
861 if (err) {
862 qDebug("failed rendering glyph %d from font", i);
863 Q_ASSERT(!err);
864 }
865
866 FT_Bitmap bm = face->glyph->bitmap;
867 x0 = face->glyph->metrics.horiBearingX >> 6;
868 y0 = (face->glyph->metrics.height - face->glyph->metrics.horiBearingY) >> 6;
869 dx = face->glyph->metrics.horiAdvance >> 6;
870 dy = 0;
871 int sz = bm.pitch * bm.rows;
872 uint *aa_glyph = 0;
873 uchar *ua_glyph = 0;
874
875 if (antialiased)
876 aa_glyph = new uint[sz];
877 else
878 ua_glyph = new uchar[sz];
879
880 // convert to GL format
881 for (int y = 0; y < bm.rows; ++y) {
882 for (int x = 0; x < bm.pitch; ++x) {
883 int c1 = y*bm.pitch + x;
884 int c2 = (bm.rows - y - 1) > 0 ? (bm.rows-y-1)*bm.pitch + x : x;
885 if (antialiased) {
886 aa_glyph[c1] = (int(color[0]*255) << 24)
887 | (int(color[1]*255) << 16)
888 | (int(color[2]*255) << 8) | bm.buffer[c2];
889 } else {
890 ua_glyph[c1] = bm.buffer[c2];
891 }
892 }
893 }
894
895 glNewList(list, GL_COMPILE);
896 if (antialiased) {
897 // calling glBitmap() is just a trick to move the current
898 // raster pos, since glGet*() won't work in display lists
899 glBitmap(0, 0, 0, 0, x0, -y0, 0);
900 glDrawPixels(bm.pitch, bm.rows, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, aa_glyph);
901 glBitmap(0, 0, 0, 0, dx-x0, y0, 0);
902 } else {
903 glBitmap(bm.pitch*8, bm.rows, -x0, y0, dx, dy, ua_glyph);
904 }
905 glEndList();
906 antialiased ? delete[] aa_glyph : delete[] ua_glyph;
907 }
908
909 engine->unlockFace();
910
911 // restore pixel unpack settings
912 glPixelStorei(GL_UNPACK_SWAP_BYTES, gl_swapbytes);
913 glPixelStorei(GL_UNPACK_LSB_FIRST, gl_lsbfirst);
914 glPixelStorei(GL_UNPACK_ROW_LENGTH, gl_rowlength);
915 glPixelStorei(GL_UNPACK_SKIP_ROWS, gl_skiprows);
916 glPixelStorei(GL_UNPACK_SKIP_PIXELS, gl_skippixels);
917 glPixelStorei(GL_UNPACK_ALIGNMENT, gl_alignment);
918}
919#endif
920
921#undef d
922void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
923{
924 QFont f(fnt);
925 QFontEngine *engine = f.d->engineForScript(QUnicodeTables::Common);
926
927 if (engine->type() == QFontEngine::Multi)
928 engine = static_cast<QFontEngineMulti *>(engine)->engine(0);
929#ifndef QT_NO_FONTCONFIG
930 if(engine->type() == QFontEngine::Freetype) {
931 qgl_use_font(static_cast<QFontEngineFT *>(engine), 0, 256, listBase);
932 return;
933 }
934#endif
935 // glXUseXFont() only works with XLFD font structures and a few GL
936 // drivers crash if 0 is passed as the font handle
937 f.setStyleStrategy(QFont::OpenGLCompatible);
938 if (f.handle() && engine->type() == QFontEngine::XLFD)
939 glXUseXFont(static_cast<Font>(f.handle()), 0, 256, listBase);
940}
941
942void *QGLContext::getProcAddress(const QString &proc) const
943{
944 typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *);
945 static qt_glXGetProcAddressARB glXGetProcAddressARB = 0;
946 static bool resolved = false;
947
948 if (resolved && !glXGetProcAddressARB)
949 return 0;
950 if (!glXGetProcAddressARB) {
951 QString glxExt = QString(QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)));
952 if (glxExt.contains(QLatin1String("GLX_ARB_get_proc_address"))) {
953#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
954 void *handle = dlopen(NULL, RTLD_LAZY);
955 if (handle) {
956 glXGetProcAddressARB = (qt_glXGetProcAddressARB) dlsym(handle, "glXGetProcAddressARB");
957 dlclose(handle);
958 }
959 if (!glXGetProcAddressARB)
960#endif
961 {
962 extern const QString qt_gl_library_name();
963 QLibrary lib(qt_gl_library_name());
964 glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB");
965 }
966 }
967 resolved = true;
968 }
969 if (!glXGetProcAddressARB)
970 return 0;
971 return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(proc.toLatin1().data()));
972}
973
974/*****************************************************************************
975 QGLOverlayWidget (Internal overlay class for X11)
976 *****************************************************************************/
977
978class QGLOverlayWidget : public QGLWidget
979{
980 Q_OBJECT
981public:
982 QGLOverlayWidget(const QGLFormat& format, QGLWidget* parent, const QGLWidget* shareWidget=0);
983
984protected:
985 void initializeGL();
986 void paintGL();
987 void resizeGL(int w, int h);
988 bool x11Event(XEvent *e) { return realWidget->x11Event(e); }
989
990private:
991 QGLWidget* realWidget;
992
993private:
994 Q_DISABLE_COPY(QGLOverlayWidget)
995};
996
997
998QGLOverlayWidget::QGLOverlayWidget(const QGLFormat& format, QGLWidget* parent,
999 const QGLWidget* shareWidget)
1000 : QGLWidget(format, parent, shareWidget ? shareWidget->d_func()->olw : 0)
1001{
1002 setAttribute(Qt::WA_X11OpenGLOverlay);
1003 realWidget = parent;
1004}
1005
1006
1007
1008void QGLOverlayWidget::initializeGL()
1009{
1010 QColor transparentColor = context()->overlayTransparentColor();
1011 if (transparentColor.isValid())
1012 qglClearColor(transparentColor);
1013 else
1014 qWarning("QGLOverlayWidget::initializeGL(): Could not get transparent color");
1015 realWidget->initializeOverlayGL();
1016}
1017
1018
1019void QGLOverlayWidget::resizeGL(int w, int h)
1020{
1021 glViewport(0, 0, w, h);
1022 realWidget->resizeOverlayGL(w, h);
1023}
1024
1025
1026void QGLOverlayWidget::paintGL()
1027{
1028 realWidget->paintOverlayGL();
1029}
1030
1031#undef Bool
1032QT_BEGIN_INCLUDE_NAMESPACE
1033#include "qgl_x11.moc"
1034QT_END_INCLUDE_NAMESPACE
1035
1036/*****************************************************************************
1037 QGLWidget UNIX/GLX-specific code
1038 *****************************************************************************/
1039void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget *shareWidget)
1040{
1041 Q_Q(QGLWidget);
1042 initContext(context, shareWidget);
1043 olw = 0;
1044
1045 if (q->isValid() && context->format().hasOverlay()) {
1046 QString olwName = q->objectName();
1047 olwName += QLatin1String("-QGL_internal_overlay_widget");
1048 olw = new QGLOverlayWidget(QGLFormat::defaultOverlayFormat(), q, shareWidget);
1049 olw->setObjectName(olwName);
1050 if (olw->isValid()) {
1051 olw->setAutoBufferSwap(false);
1052 olw->setFocusProxy(q);
1053 }
1054 else {
1055 delete olw;
1056 olw = 0;
1057 glcx->d_func()->glFormat.setOverlay(false);
1058 }
1059 }
1060}
1061
1062bool QGLWidgetPrivate::renderCxPm(QPixmap* pm)
1063{
1064 Q_Q(QGLWidget);
1065 if (((XVisualInfo*)glcx->d_func()->vi)->depth != pm->depth())
1066 return false;
1067
1068 GLXPixmap glPm;
1069#if defined(GLX_MESA_pixmap_colormap) && defined(QGL_USE_MESA_EXT)
1070 glPm = glXCreateGLXPixmapMESA(X11->display,
1071 (XVisualInfo*)glcx->vi,
1072 (Pixmap)pm->handle(),
1073 qt_gl_choose_cmap(pm->X11->display,
1074 (XVisualInfo*)glcx->vi));
1075#else
1076 glPm = (quint32)glXCreateGLXPixmap(X11->display,
1077 (XVisualInfo*)glcx->d_func()->vi,
1078 (Pixmap)pm->handle());
1079#endif
1080
1081 if (!glXMakeCurrent(X11->display, glPm, (GLXContext)glcx->d_func()->cx)) {
1082 glXDestroyGLXPixmap(X11->display, glPm);
1083 return false;
1084 }
1085
1086 glDrawBuffer(GL_FRONT);
1087 if (!glcx->initialized())
1088 q->glInit();
1089 q->resizeGL(pm->width(), pm->height());
1090 q->paintGL();
1091 glFlush();
1092 q->makeCurrent();
1093 glXDestroyGLXPixmap(X11->display, glPm);
1094 q->resizeGL(q->width(), q->height());
1095 return true;
1096}
1097
1098/*! \internal
1099 Free up any allocated colormaps. This fn is only called for
1100 top-level widgets.
1101*/
1102void QGLWidgetPrivate::cleanupColormaps()
1103{
1104 if (!cmap.handle()) {
1105 return;
1106 } else {
1107 XFreeColormap(X11->display, (Colormap) cmap.handle());
1108 cmap.setHandle(0);
1109 }
1110}
1111
1112void QGLWidget::setMouseTracking(bool enable)
1113{
1114 Q_D(QGLWidget);
1115 if (d->olw)
1116 d->olw->setMouseTracking(enable);
1117 QWidget::setMouseTracking(enable);
1118}
1119
1120
1121void QGLWidget::resizeEvent(QResizeEvent *)
1122{
1123 Q_D(QGLWidget);
1124 if (!isValid())
1125 return;
1126 makeCurrent();
1127 if (!d->glcx->initialized())
1128 glInit();
1129 glXWaitX();
1130 resizeGL(width(), height());
1131 if (d->olw)
1132 d->olw->setGeometry(rect());
1133}
1134
1135const QGLContext* QGLWidget::overlayContext() const
1136{
1137 Q_D(const QGLWidget);
1138 if (d->olw)
1139 return d->olw->context();
1140 else
1141 return 0;
1142}
1143
1144
1145void QGLWidget::makeOverlayCurrent()
1146{
1147 Q_D(QGLWidget);
1148 if (d->olw)
1149 d->olw->makeCurrent();
1150}
1151
1152
1153void QGLWidget::updateOverlayGL()
1154{
1155 Q_D(QGLWidget);
1156 if (d->olw)
1157 d->olw->updateGL();
1158}
1159
1160/*!
1161 \internal
1162
1163 Sets a new QGLContext, \a context, for this QGLWidget, using the
1164 shared context, \a shareContext. If \a deleteOldContext is true,
1165 the original context is deleted; otherwise it is overridden.
1166*/
1167void QGLWidget::setContext(QGLContext *context,
1168 const QGLContext* shareContext,
1169 bool deleteOldContext)
1170{
1171 Q_D(QGLWidget);
1172 if (context == 0) {
1173 qWarning("QGLWidget::setContext: Cannot set null context");
1174 return;
1175 }
1176 if (!context->deviceIsPixmap() && context->device() != this) {
1177 qWarning("QGLWidget::setContext: Context must refer to this widget");
1178 return;
1179 }
1180
1181 if (d->glcx)
1182 d->glcx->doneCurrent();
1183 QGLContext* oldcx = d->glcx;
1184 d->glcx = context;
1185
1186
1187 if (parentWidget()) {
1188 // force creation of delay-created widgets
1189 parentWidget()->winId();
1190 if (parentWidget()->x11Info().screen() != x11Info().screen())
1191 d_func()->xinfo = parentWidget()->d_func()->xinfo;
1192 }
1193
1194 bool createFailed = false;
1195 if (!d->glcx->isValid()) {
1196 if (!d->glcx->create(shareContext ? shareContext : oldcx))
1197 createFailed = true;
1198 }
1199 if (createFailed) {
1200 if (deleteOldContext)
1201 delete oldcx;
1202 return;
1203 }
1204
1205 if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
1206 if (deleteOldContext)
1207 delete oldcx;
1208 return;
1209 }
1210
1211 bool visible = isVisible();
1212 if (visible)
1213 hide();
1214
1215 XVisualInfo *vi = (XVisualInfo*)d->glcx->d_func()->vi;
1216 XSetWindowAttributes a;
1217
1218 QColormap colmap = QColormap::instance(vi->screen);
1219 a.colormap = qt_gl_choose_cmap(QX11Info::display(), vi); // find best colormap
1220 a.background_pixel = colmap.pixel(palette().color(backgroundRole()));
1221 a.border_pixel = colmap.pixel(Qt::black);
1222 Window p = RootWindow(X11->display, vi->screen);
1223 if (parentWidget())
1224 p = parentWidget()->winId();
1225
1226 Window w = XCreateWindow(X11->display, p, x(), y(), width(), height(),
1227 0, vi->depth, InputOutput, vi->visual,
1228 CWBackPixel|CWBorderPixel|CWColormap, &a);
1229 Window *cmw;
1230 Window *cmwret;
1231 int count;
1232 if (XGetWMColormapWindows(X11->display, window()->winId(),
1233 &cmwret, &count)) {
1234 cmw = new Window[count+1];
1235 memcpy((char *)cmw, (char *)cmwret, sizeof(Window)*count);
1236 XFree((char *)cmwret);
1237 int i;
1238 for (i=0; i<count; i++) {
1239 if (cmw[i] == winId()) { // replace old window
1240 cmw[i] = w;
1241 break;
1242 }
1243 }
1244 if (i >= count) // append new window
1245 cmw[count++] = w;
1246 } else {
1247 count = 1;
1248 cmw = new Window[count];
1249 cmw[0] = w;
1250 }
1251
1252#if defined(GLX_MESA_release_buffers) && defined(QGL_USE_MESA_EXT)
1253 if (oldcx && oldcx->windowCreated())
1254 glXReleaseBuffersMESA(X11->display, winId());
1255#endif
1256 if (deleteOldContext)
1257 delete oldcx;
1258 oldcx = 0;
1259
1260 if (testAttribute(Qt::WA_WState_Created))
1261 create(w);
1262 else
1263 d->createWinId(w);
1264 XSetWMColormapWindows(X11->display, window()->winId(), cmw, count);
1265 delete [] cmw;
1266
1267 // calling QWidget::create() will always result in a new paint
1268 // engine being created - get rid of it and replace it with our
1269 // own
1270
1271 if (visible)
1272 show();
1273 XFlush(X11->display);
1274 d->glcx->setWindowCreated(true);
1275}
1276
1277const QGLColormap & QGLWidget::colormap() const
1278{
1279 Q_D(const QGLWidget);
1280 return d->cmap;
1281}
1282
1283/*\internal
1284 Store color values in the given colormap.
1285*/
1286static void qStoreColors(QWidget * tlw, Colormap cmap,
1287 const QGLColormap & cols)
1288{
1289 Q_UNUSED(tlw);
1290 XColor c;
1291 QRgb color;
1292
1293 for (int i = 0; i < cols.size(); i++) {
1294 color = cols.entryRgb(i);
1295 c.pixel = i;
1296 c.red = (ushort)((qRed(color) / 255.0) * 65535.0 + 0.5);
1297 c.green = (ushort)((qGreen(color) / 255.0) * 65535.0 + 0.5);
1298 c.blue = (ushort)((qBlue(color) / 255.0) * 65535.0 + 0.5);
1299 c.flags = DoRed | DoGreen | DoBlue;
1300 XStoreColor(X11->display, cmap, &c);
1301 }
1302}
1303
1304/*\internal
1305 Check whether the given visual supports dynamic colormaps or not.
1306*/
1307static bool qCanAllocColors(QWidget * w)
1308{
1309 bool validVisual = false;
1310 int numVisuals;
1311 long mask;
1312 XVisualInfo templ;
1313 XVisualInfo * visuals;
1314 VisualID id = XVisualIDFromVisual((Visual *) w->window()->x11Info().visual());
1315
1316 mask = VisualScreenMask;
1317 templ.screen = w->x11Info().screen();
1318 visuals = XGetVisualInfo(X11->display, mask, &templ, &numVisuals);
1319
1320 for (int i = 0; i < numVisuals; i++) {
1321 if (visuals[i].visualid == id) {
1322 switch (visuals[i].c_class) {
1323 case TrueColor:
1324 case StaticColor:
1325 case StaticGray:
1326 case XGrayScale:
1327 validVisual = false;
1328 break;
1329 case DirectColor:
1330 case PseudoColor:
1331 validVisual = true;
1332 break;
1333 }
1334 break;
1335 }
1336 }
1337 XFree(visuals);
1338
1339 if (!validVisual)
1340 return false;
1341 return true;
1342}
1343
1344
1345void QGLWidget::setColormap(const QGLColormap & c)
1346{
1347 Q_D(QGLWidget);
1348 QWidget * tlw = window(); // must return a valid widget
1349
1350 d->cmap = c;
1351 if (!d->cmap.handle())
1352 return;
1353
1354 if (!qCanAllocColors(this)) {
1355 qWarning("QGLWidget::setColormap: Cannot create a read/write "
1356 "colormap for this visual");
1357 return;
1358 }
1359
1360 // If the child GL widget is not of the same visual class as the
1361 // toplevel widget we will get in trouble..
1362 Window wid = tlw->winId();
1363 Visual * vis = (Visual *) tlw->x11Info().visual();;
1364 VisualID cvId = XVisualIDFromVisual((Visual *) x11Info().visual());
1365 VisualID tvId = XVisualIDFromVisual((Visual *) tlw->x11Info().visual());
1366 if (cvId != tvId) {
1367 wid = winId();
1368 vis = (Visual *) x11Info().visual();
1369 }
1370
1371 if (!d->cmap.handle()) // allocate a cmap if necessary
1372 d->cmap.setHandle(XCreateColormap(X11->display, wid, vis, AllocAll));
1373
1374 qStoreColors(this, (Colormap) d->cmap.handle(), c);
1375 XSetWindowColormap(X11->display, wid, (Colormap) d->cmap.handle());
1376
1377 // tell the wm that this window has a special colormap
1378 Window * cmw;
1379 Window * cmwret;
1380 int count;
1381 if (XGetWMColormapWindows(X11->display, tlw->winId(), &cmwret, &count))
1382 {
1383 cmw = new Window[count+1];
1384 memcpy((char *) cmw, (char *) cmwret, sizeof(Window) * count);
1385 XFree((char *) cmwret);
1386 int i;
1387 for (i = 0; i < count; i++) {
1388 if (cmw[i] == winId()) {
1389 break;
1390 }
1391 }
1392 if (i >= count) // append new window only if not in the list
1393 cmw[count++] = winId();
1394 } else {
1395 count = 1;
1396 cmw = new Window[count];
1397 cmw[0] = winId();
1398 }
1399 XSetWMColormapWindows(X11->display, tlw->winId(), cmw, count);
1400 delete [] cmw;
1401}
1402
1403void QGLExtensions::init()
1404{
1405 static bool init_done = false;
1406
1407 if (init_done)
1408 return;
1409 init_done = true;
1410
1411 QGLWidget dmy;
1412 dmy.makeCurrent();
1413 init_extensions();
1414
1415 // nvidia 9x.xx unix drivers contain a bug which requires us to call glFinish before releasing an fbo
1416 // to avoid painting artifacts
1417 const QByteArray versionString(reinterpret_cast<const char*>(glGetString(GL_VERSION)));
1418 const int pos = versionString.indexOf("NVIDIA");
1419 if (pos >= 0) {
1420 const float nvidiaDriverVersion = versionString.mid(pos + strlen("NVIDIA")).toFloat();
1421 nvidiaFboNeedsFinish = nvidiaDriverVersion >= 90.0 && nvidiaDriverVersion < 100.0;
1422 }
1423}
1424
1425QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.