Re-apply change 353dcfd307853da289fdd245410e2e07358624a0 by Friedemann Kleint
[qt-netbsd.git] / src / opengl / qgl_mac.mm
blob7930d8e5c3f7f306c7ddfdd161414de969ca7f3b
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Nokia Corporation (qt-info@nokia.com)
5 **
6 ** This file is part of the QtOpenGL module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** No Commercial Usage
10 ** This file contains pre-release code and may not be distributed.
11 ** You may use this file in accordance with the terms and conditions
12 ** contained in the either Technology Preview License Agreement or the
13 ** Beta Release License Agreement.
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.
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.
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.
36 ** If you are unsure which license is appropriate for your use, please
37 ** contact the sales department at http://www.qtsoftware.com/contact.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include "qgl.h"
44 // There are functions that are deprecated in 10.5, but really there's no way around them
45 // for Carbon, so just undefine them.
46 #undef DEPRECATED_ATTRIBUTE
47 #define DEPRECATED_ATTRIBUTE
48 #if defined(Q_WS_MAC)
49 #ifndef QT_MAC_USE_COCOA
50 #ifdef qDebug
51 #    undef qDebug
52 #    include <AGL/agl.h>
53 #    include <AGL/aglRenderers.h>
54 #    include <OpenGL/gl.h>
55 #    ifdef QT_NO_DEBUG
56 #        define qDebug qt_noop(),1?(void)0:qDebug
57 #    endif
58 #else
59 #    include <AGL/agl.h>
60 #    include <AGL/aglRenderers.h>
61 #    include <OpenGL/gl.h>
62 #endif
63 #else
64 #include <private/qcocoaview_mac_p.h>
65 #endif
68 #include <OpenGL/gl.h>
69 #include <CoreServices/CoreServices.h>
70 #include <private/qfont_p.h>
71 #include <private/qfontengine_p.h>
72 #include <private/qgl_p.h>
73 #include <private/qpaintengine_opengl_p.h>
74 #include <private/qt_mac_p.h>
75 #include <qpixmap.h>
76 #include <qtimer.h>
77 #include <qapplication.h>
78 #include <qstack.h>
79 #include <qdesktopwidget.h>
80 #include <qdebug.h>
82 QT_BEGIN_NAMESPACE
83 #ifdef QT_MAC_USE_COCOA
84 QT_END_NAMESPACE
86 QT_FORWARD_DECLARE_CLASS(QWidget)
87 QT_FORWARD_DECLARE_CLASS(QWidgetPrivate)
88 QT_FORWARD_DECLARE_CLASS(QGLWidgetPrivate)
90 QT_BEGIN_NAMESPACE
92 void *qt_current_nsopengl_context()
94     return [NSOpenGLContext currentContext];
97 static GLint attribValue(NSOpenGLPixelFormat *fmt, NSOpenGLPixelFormatAttribute attrib)
99     GLint res;
100     [fmt getValues:&res forAttribute:attrib forVirtualScreen:0];
101     return res;
104 static int def(int val, int defVal)
106     return val != -1 ? val : defVal;
108 #else
109 QRegion qt_mac_get_widget_rgn(const QWidget *widget);
110 #endif
112 extern quint32 *qt_mac_pixmap_get_base(const QPixmap *);
113 extern int qt_mac_pixmap_get_bytes_per_line(const QPixmap *);
114 extern RgnHandle qt_mac_get_rgn(); //qregion_mac.cpp
115 extern void qt_mac_dispose_rgn(RgnHandle); //qregion_mac.cpp
116 extern QRegion qt_mac_convert_mac_region(RgnHandle); //qregion_mac.cpp
117 extern void qt_mac_to_pascal_string(QString s, Str255 str, TextEncoding encoding=0, int len=-1);  //qglobal.cpp
119 bool QGLFormat::hasOpenGL()
121     return true;
124 bool QGLFormat::hasOpenGLOverlays()
126     return false;
129 bool QGLContext::chooseContext(const QGLContext *shareContext)
131     QMacCocoaAutoReleasePool pool;
132     Q_D(QGLContext);
133     d->cx = 0;
134     d->vi = chooseMacVisual(0);
135     if (!d->vi)
136         return false;
138 #ifndef QT_MAC_USE_COCOA
139     AGLPixelFormat fmt = (AGLPixelFormat)d->vi;
140     GLint res;
141     aglDescribePixelFormat(fmt, AGL_LEVEL, &res);
142     d->glFormat.setPlane(res);
143     if (deviceIsPixmap())
144         res = 0;
145     else
146         aglDescribePixelFormat(fmt, AGL_DOUBLEBUFFER, &res);
147     d->glFormat.setDoubleBuffer(res);
148     aglDescribePixelFormat(fmt, AGL_DEPTH_SIZE, &res);
149     d->glFormat.setDepth(res);
150     if (d->glFormat.depth())
151         d->glFormat.setDepthBufferSize(res);
152     aglDescribePixelFormat(fmt, AGL_RGBA, &res);
153     d->glFormat.setRgba(res);
154     aglDescribePixelFormat(fmt, AGL_RED_SIZE, &res);
155     d->glFormat.setRedBufferSize(res);
156     aglDescribePixelFormat(fmt, AGL_GREEN_SIZE, &res);
157     d->glFormat.setGreenBufferSize(res);
158     aglDescribePixelFormat(fmt, AGL_BLUE_SIZE, &res);
159     d->glFormat.setBlueBufferSize(res);
160     aglDescribePixelFormat(fmt, AGL_ALPHA_SIZE, &res);
161     d->glFormat.setAlpha(res);
162     if (d->glFormat.alpha())
163         d->glFormat.setAlphaBufferSize(res);
164     aglDescribePixelFormat(fmt, AGL_ACCUM_RED_SIZE, &res);
165     // Bug in Apple OpenGL (rdr://5015603), when we don't have an accumulation
166     // buffer, it still claims that we have a 16-bit one (which is pretty rare).
167     // So, we just assume we can never have a buffer that small.
168     d->glFormat.setAccum(res > 5);
169     if (d->glFormat.accum())
170         d->glFormat.setAccumBufferSize(res);
171     aglDescribePixelFormat(fmt, AGL_STENCIL_SIZE, &res);
172     d->glFormat.setStencil(res);
173     if (d->glFormat.stencil())
174         d->glFormat.setStencilBufferSize(res);
175     aglDescribePixelFormat(fmt, AGL_STEREO, &res);
176     d->glFormat.setStereo(res);
177     aglDescribePixelFormat(fmt, AGL_SAMPLE_BUFFERS_ARB, &res);
178     d->glFormat.setSampleBuffers(res);
179     if (d->glFormat.sampleBuffers()) {
180         aglDescribePixelFormat(fmt, AGL_SAMPLES_ARB, &res);
181         d->glFormat.setSamples(res);
182     }
183 #else
184     NSOpenGLPixelFormat *fmt = static_cast<NSOpenGLPixelFormat *>(d->vi);
186     d->glFormat = QGLFormat();
188     // ### make sure to reset other options
189     d->glFormat.setDoubleBuffer(attribValue(fmt, NSOpenGLPFADoubleBuffer));
191     int depthSize = attribValue(fmt, NSOpenGLPFADepthSize);
192     d->glFormat.setDepth(depthSize > 0);
193     if (depthSize > 0)
194         d->glFormat.setDepthBufferSize(depthSize);
196     int alphaSize = attribValue(fmt, NSOpenGLPFAAlphaSize);
197     d->glFormat.setAlpha(alphaSize > 0);
198     if (alphaSize > 0)
199         d->glFormat.setAlphaBufferSize(alphaSize);
201     int accumSize = attribValue(fmt, NSOpenGLPFAAccumSize);
202     d->glFormat.setAccum(accumSize > 0);
203     if (accumSize > 0)
204         d->glFormat.setAccumBufferSize(accumSize);
206     int stencilSize = attribValue(fmt, NSOpenGLPFAStencilSize);
207     d->glFormat.setStencil(stencilSize > 0);
208     if (stencilSize > 0)
209         d->glFormat.setStencilBufferSize(stencilSize);
211     d->glFormat.setStereo(attribValue(fmt, NSOpenGLPFAStereo));
213     int sampleBuffers = attribValue(fmt, NSOpenGLPFASampleBuffers);
214     d->glFormat.setSampleBuffers(sampleBuffers);
215     if (sampleBuffers > 0)
216         d->glFormat.setSamples(attribValue(fmt, NSOpenGLPFASamples));
217 #endif
218     if (shareContext && (!shareContext->isValid() || !shareContext->d_func()->cx)) {
219         qWarning("QGLContext::chooseContext: Cannot share with invalid context");
220         shareContext = 0;
221     }
223     // sharing between rgba and color-index will give wrong colors
224     if (shareContext && (format().rgba() != shareContext->format().rgba()))
225         shareContext = 0;
227 #ifndef QT_MAC_USE_COCOA
228     AGLContext ctx = aglCreateContext(fmt, (AGLContext) (shareContext ? shareContext->d_func()->cx : 0));
229 #else
230     NSOpenGLContext *ctx = [[NSOpenGLContext alloc] initWithFormat:fmt
231         shareContext:(shareContext ? static_cast<NSOpenGLContext *>(shareContext->d_func()->cx)
232                                    : 0)];
233 #endif
234     if (!ctx) {
235 #ifndef QT_MAC_USE_COCOA
236         GLenum err = aglGetError();
237         if (err == AGL_BAD_MATCH || err == AGL_BAD_CONTEXT) {
238             if (shareContext && shareContext->d_func()->cx) {
239                 qWarning("QGLContext::chooseContext(): Context sharing mismatch!");
240                 if (!(ctx = aglCreateContext(fmt, 0)))
241                     return false;
242                 shareContext = 0;
243             }
244         }
245 #else
246         if (shareContext) {
247             ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:0];
248             if (ctx) {
249                 qWarning("QGLContext::chooseContext: Context sharing mismatch");
250                 shareContext = 0;
251             }
252         }
253 #endif
254         if (!ctx) {
255             qWarning("QGLContext::chooseContext: Unable to create QGLContext");
256             return false;
257         }
258     }
259     d->cx = ctx;
260     if (shareContext && shareContext->d_func()->cx) {
261         QGLContext *share = const_cast<QGLContext *>(shareContext);
262         d->sharing = true;
263         share->d_func()->sharing = true;
264     }
265     if (deviceIsPixmap())
266         updatePaintDevice();
268     // vblank syncing
269     GLint interval = d->reqFormat.swapInterval();
270     if (interval != -1) {
271 #ifndef QT_MAC_USE_COCOA
272         aglSetInteger((AGLContext)d->cx, AGL_SWAP_INTERVAL, &interval);
273         if (interval != 0)
274             aglEnable((AGLContext)d->cx, AGL_SWAP_INTERVAL);
275         else
276             aglDisable((AGLContext)d->cx, AGL_SWAP_INTERVAL);
277 #else
278         [ctx setValues:&interval forParameter:NSOpenGLCPSwapInterval];
279 #endif
280     }
281 #ifndef QT_MAC_USE_COCOA
282     aglGetInteger((AGLContext)d->cx, AGL_SWAP_INTERVAL, &interval);
283 #else
284     [ctx getValues:&interval forParameter:NSOpenGLCPSwapInterval];
285 #endif
286     d->glFormat.setSwapInterval(interval);
287     return true;
290 void *QGLContextPrivate::tryFormat(const QGLFormat &format)
292     static const int Max = 40;
293 #ifndef QT_MAC_USE_COCOA
294     GLint attribs[Max], cnt = 0;
295     bool device_is_pixmap = (paintDevice->devType() == QInternal::Pixmap);
297     attribs[cnt++] = AGL_RGBA;
298     attribs[cnt++] = AGL_BUFFER_SIZE;
299     attribs[cnt++] = device_is_pixmap ? static_cast<QPixmap *>(paintDevice)->depth() : 32;
300     attribs[cnt++] = AGL_LEVEL;
301     attribs[cnt++] = format.plane();
303     if (format.redBufferSize() != -1) {
304         attribs[cnt++] = AGL_RED_SIZE;
305         attribs[cnt++] = format.redBufferSize();
306     }
307     if (format.greenBufferSize() != -1) {
308         attribs[cnt++] = AGL_GREEN_SIZE;
309         attribs[cnt++] = format.greenBufferSize();
310     }
311     if (format.blueBufferSize() != -1) {
312         attribs[cnt++] = AGL_BLUE_SIZE;
313         attribs[cnt++] = format.blueBufferSize();
314     }
315     if (device_is_pixmap) {
316         attribs[cnt++] = AGL_PIXEL_SIZE;
317         attribs[cnt++] = static_cast<QPixmap *>(paintDevice)->depth();
318         attribs[cnt++] = AGL_OFFSCREEN;
319         if (!format.alpha()) {
320             attribs[cnt++] = AGL_ALPHA_SIZE;
321             attribs[cnt++] = 8;
322         }
323     } else {
324         if (format.doubleBuffer())
325             attribs[cnt++] = AGL_DOUBLEBUFFER;
326     }
328     if (format.stereo())
329         attribs[cnt++] = AGL_STEREO;
330     if (format.alpha()) {
331         attribs[cnt++] = AGL_ALPHA_SIZE;
332         attribs[cnt++] = format.alphaBufferSize() == -1 ? 8 : format.alphaBufferSize();
333     }
334     if (format.stencil()) {
335         attribs[cnt++] = AGL_STENCIL_SIZE;
336         attribs[cnt++] = format.stencilBufferSize() == -1 ? 8 : format.stencilBufferSize();
337     }
338     if (format.depth()) {
339         attribs[cnt++] = AGL_DEPTH_SIZE;
340         attribs[cnt++] = format.depthBufferSize() == -1 ? 32 : format.depthBufferSize();
341     }
342     if (format.accum()) {
343         attribs[cnt++] = AGL_ACCUM_RED_SIZE;
344         attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
345         attribs[cnt++] = AGL_ACCUM_BLUE_SIZE;
346         attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
347         attribs[cnt++] = AGL_ACCUM_GREEN_SIZE;
348         attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
349         attribs[cnt++] = AGL_ACCUM_ALPHA_SIZE;
350         attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
351     }
352     if (format.sampleBuffers()) {
353         attribs[cnt++] = AGL_SAMPLE_BUFFERS_ARB;
354         attribs[cnt++] = 1;
355         attribs[cnt++] = AGL_SAMPLES_ARB;
356         attribs[cnt++] = format.samples() == -1 ? 4 : format.samples();
357     }
359     attribs[cnt] = AGL_NONE;
360     Q_ASSERT(cnt < Max);
361     return aglChoosePixelFormat(0, 0, attribs);
362 #else
363     NSOpenGLPixelFormatAttribute attribs[Max];
364     int cnt = 0;
365     int devType = paintDevice->devType();
366     bool device_is_pixmap = (devType == QInternal::Pixmap);
367     int depth = device_is_pixmap ? static_cast<QPixmap *>(paintDevice)->depth() : 32;
369     attribs[cnt++] = NSOpenGLPFAColorSize;
370     attribs[cnt++] = depth;
372     if (device_is_pixmap) {
373         attribs[cnt++] = NSOpenGLPFAOffScreen;
374     } else {
375         if (format.doubleBuffer())
376             attribs[cnt++] = NSOpenGLPFADoubleBuffer;
377     }
378     if (glFormat.stereo())
379         attribs[cnt++] = NSOpenGLPFAStereo;
380     if (device_is_pixmap || format.alpha()) {
381         attribs[cnt++] = NSOpenGLPFAAlphaSize;
382         attribs[cnt++] = def(format.alphaBufferSize(), 8);
383     }
384     if (format.stencil()) {
385         attribs[cnt++] = NSOpenGLPFAStencilSize;
386         attribs[cnt++] = def(format.stencilBufferSize(), 8);
387     }
388     if (format.depth()) {
389         attribs[cnt++] = NSOpenGLPFADepthSize;
390         attribs[cnt++] = def(format.depthBufferSize(), 32);
391     }
392     if (format.accum()) {
393         attribs[cnt++] = NSOpenGLPFAAccumSize;
394         attribs[cnt++] = def(format.accumBufferSize(), 1);
395     }
396     if (format.sampleBuffers()) {
397         attribs[cnt++] = NSOpenGLPFASampleBuffers;
398         attribs[cnt++] = 1;
399         attribs[cnt++] = NSOpenGLPFASamples;
400         attribs[cnt++] = def(format.samples(), 4);
401     }
403     if (format.directRendering())
404         attribs[cnt++] = NSOpenGLPFAAccelerated;
406     if (devType == QInternal::Pbuffer)
407         attribs[cnt++] = NSOpenGLPFAPixelBuffer;
409     attribs[cnt] = 0;
410     Q_ASSERT(cnt < Max);
411     return [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
412 #endif
415 void QGLContextPrivate::clearDrawable()
417     [static_cast<NSOpenGLContext *>(cx) clearDrawable];
421     \bold{Mac OS X only:} This virtual function tries to find a visual that
422     matches the format, reducing the demands if the original request
423     cannot be met.
425     The algorithm for reducing the demands of the format is quite
426     simple-minded, so override this method in your subclass if your
427     application has spcific requirements on visual selection.
429     The \a handle argument is always zero and is not used
431     \sa chooseContext()
434 void *QGLContext::chooseMacVisual(GDHandle /* handle */)
436     Q_D(QGLContext);
438     void *fmt = d->tryFormat(d->glFormat);
439     if (!fmt && d->glFormat.stereo()) {
440         d->glFormat.setStereo(false);
441         fmt = d->tryFormat(d->glFormat);
442     }
443     if (!fmt && d->glFormat.sampleBuffers()) {
444         d->glFormat.setSampleBuffers(false);
445         fmt = d->tryFormat(d->glFormat);
446     }
447     if (!fmt)
448         qWarning("QGLContext::chooseMacVisual: Unable to choose a pixel format");
449     return fmt;
452 void QGLContext::reset()
454     Q_D(QGLContext);
455     if (!d->valid)
456         return;
457     d->cleanup();
458     doneCurrent();
459 #ifndef QT_MAC_USE_COCOA
460     if (d->cx)
461         aglDestroyContext((AGLContext)d->cx);
462 #else
463     [static_cast<NSOpenGLContext *>(d->cx) release];
464 #endif
465     d->cx = 0;
466 #ifndef QT_MAC_USE_COCOA
467     if (d->vi)
468         aglDestroyPixelFormat((AGLPixelFormat)d->vi);
469 #else
470     [static_cast<NSOpenGLPixelFormat *>(d->vi) release];
471 #endif
472     d->vi = 0;
473     d->crWin = false;
474     d->sharing = false;
475     d->valid = false;
476     d->transpColor = QColor();
477     d->initDone = false;
478     qgl_share_reg()->removeShare(this);
481 void QGLContext::makeCurrent()
483     Q_D(QGLContext);
485     if (!d->valid) {
486         qWarning("QGLContext::makeCurrent: Cannot make invalid context current");
487         return;
488     }
489 #ifndef QT_MAC_USE_COCOA
490     aglSetCurrentContext((AGLContext)d->cx);
491     if (d->update)
492         updatePaintDevice();
493 #else
494     [static_cast<NSOpenGLContext *>(d->cx) makeCurrentContext];
495 #endif
496     currentCtx = this;
497     if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
498         qgl_context_storage.setLocalData(new QGLThreadContext);
499     if (qgl_context_storage.hasLocalData())
500         qgl_context_storage.localData()->context = this;
503 #ifndef QT_MAC_USE_COCOA
505     Returns the effective scale factor for a widget. For this value to be
506     different than 1, the following must be true:
507     - The system scale factor must be greater than 1.
508     - The widget window must have WA_MacFrameworkScaled set.
510 float qt_mac_get_scale_factor(QWidget *widget)
512     if (!widget | !widget->window())
513         return 1;
515     if (widget->window()->testAttribute(Qt::WA_MacFrameworkScaled) == false)
516         return 1;
518     float systemScale = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4 ? HIGetScaleFactor() : 1;
519     if (systemScale == float(1))
520         return 1;
522     return systemScale;
524 #endif
526 /*! \internal
528 void QGLContext::updatePaintDevice()
530     Q_D(QGLContext);
531 #ifndef QT_MAC_USE_COCOA
532     d->update = false;
533     if (d->paintDevice->devType() == QInternal::Widget) {
534         //get control information
535         QWidget *w = (QWidget *)d->paintDevice;
536         HIViewRef hiview = (HIViewRef)w->winId();
537         WindowRef window = HIViewGetWindow(hiview);
538 #ifdef DEBUG_OPENGL_REGION_UPDATE
539         static int serial_no_gl = 0;
540         qDebug("[%d] %p setting on %s::%s %p/%p [%s]", ++serial_no_gl, w,
541                 w->metaObject()->className(), w->objectName().toLatin1().constData(),
542                 hiview, window, w->handle() ? "Inside" : "Outside");
543 #endif
545         //update drawable
546         if (0 && w->isWindow() && w->isFullScreen()) {
547             aglSetDrawable((AGLContext)d->cx, 0);
548             aglSetFullScreen((AGLContext)d->cx, w->width(), w->height(), 0, QApplication::desktop()->screenNumber(w));
549             w->hide();
550         } else {
551             AGLDrawable old_draw = aglGetDrawable((AGLContext)d->cx), new_draw = GetWindowPort(window);
552             if (old_draw != new_draw)
553                 aglSetDrawable((AGLContext)d->cx, new_draw);
554         }
556         float scale  = qt_mac_get_scale_factor(w);
558         if (!w->isWindow()) {
559             QRegion clp = qt_mac_get_widget_rgn(w); //get drawable area
561 #ifdef DEBUG_OPENGL_REGION_UPDATE
562             if (clp.isEmpty()) {
563                 qDebug("  Empty area!");
564             } else {
565                 QVector<QRect> rs = clp.rects();
566                 for(int i = 0; i < rs.count(); i++)
567                     qDebug("  %d %d %d %d", rs[i].x(), rs[i].y(), rs[i].width(), rs[i].height());
568             }
569 #endif
570             //update the clip
571             if (!aglIsEnabled((AGLContext)d->cx, AGL_BUFFER_RECT))
572                 aglEnable((AGLContext)d->cx, AGL_BUFFER_RECT);
573             if (clp.isEmpty()) {
574                 GLint offs[4] = { 0, 0, 0, 0 };
575                 aglSetInteger((AGLContext)d->cx, AGL_BUFFER_RECT, offs);
576                 if (aglIsEnabled((AGLContext)d->cx, AGL_CLIP_REGION))
577                     aglDisable((AGLContext)d->cx, AGL_CLIP_REGION);
578             } else {
579                 HIPoint origin = { 0., 0. };
580                 HIViewConvertPoint(&origin, HIViewRef(w->winId()), 0);
581                 const GLint offs[4] = { qRound(origin.x),
582                     w->window()->frameGeometry().height() * scale
583                         - (qRound(origin.y) + w->height() * scale),
584                     w->width() * scale, w->height() * scale};
586                 RgnHandle region = clp.handle(true);
588                 if (scale != float(1)) {
589                     // Sacle the clip region by the scale factor
590                     Rect regionBounds;
591                     GetRegionBounds(region, &regionBounds);
592                     Rect regionBoundsDest = regionBounds;
593                     regionBoundsDest.bottom *= scale;
594                     regionBoundsDest.right *= scale;
595                     MapRgn(region, &regionBounds, &regionBoundsDest);
596                 }
598                 aglSetInteger((AGLContext)d->cx, AGL_BUFFER_RECT, offs);
599                 aglSetInteger((AGLContext)d->cx, AGL_CLIP_REGION, (const GLint *)region);
600                 if (!aglIsEnabled((AGLContext)d->cx, AGL_CLIP_REGION))
601                     aglEnable((AGLContext)d->cx, AGL_CLIP_REGION);
602             }
603         } else {
604             // Set the buffer rect for top-level gl contexts when scaled.
605             if (scale != float(1)) {
606                 aglEnable((AGLContext)d->cx, AGL_BUFFER_RECT);
607                 const GLint offs[4] = { 0, 0,  w->width() * scale , w->height() * scale};
608                 aglSetInteger((AGLContext)d->cx, AGL_BUFFER_RECT, offs);
609             }
610         }
611     } else if (d->paintDevice->devType() == QInternal::Pixmap) {
612         QPixmap *pm = (QPixmap *)d->paintDevice;
613         PixMapHandle mac_pm = GetGWorldPixMap((GWorldPtr)pm->macQDHandle());
614         aglSetOffScreen((AGLContext)d->cx, pm->width(), pm->height(),
615                 GetPixRowBytes(mac_pm), GetPixBaseAddr(mac_pm));
616     } else {
617         qWarning("QGLContext::updatePaintDevice(): Not sure how to render OpenGL on this device!");
618     }
619     aglUpdateContext((AGLContext)d->cx);
621 #else
622     QMacCocoaAutoReleasePool pool;
624     if (d->paintDevice->devType() == QInternal::Widget) {
625         //get control information
626         QWidget *w = (QWidget *)d->paintDevice;
627         NSView *view = qt_mac_nativeview_for(w);
629         // ideally we would use QWidget::isVisible(), but we get "invalid drawable" errors
630         if (![(NSWindow *)qt_mac_window_for(w) isVisible])
631             return;
632         if ([static_cast<NSOpenGLContext *>(d->cx) view] != view && ![view isHidden])
633             [static_cast<NSOpenGLContext *>(d->cx) setView:view];
634     } else if (d->paintDevice->devType() == QInternal::Pixmap) {
635         const QPixmap *pm = static_cast<const QPixmap *>(d->paintDevice);
636         [static_cast<NSOpenGLContext *>(d->cx) setOffScreen:qt_mac_pixmap_get_base(pm)
637                                                       width:pm->width()
638                                                      height:pm->height()
639                                                    rowbytes:qt_mac_pixmap_get_bytes_per_line(pm)];
640     } else {
641         qWarning("QGLContext::updatePaintDevice: Not sure how to render OpenGL on this device");
642     }
643     [static_cast<NSOpenGLContext *>(d->cx) update];
644 #endif
647 void QGLContext::doneCurrent()
650     if (
651 #ifndef QT_MAC_USE_COCOA
652         aglGetCurrentContext() != (AGLContext) d_func()->cx
653 #else
654         [NSOpenGLContext currentContext] != d_func()->cx
655 #endif
656        )
657         return;
659     currentCtx = 0;
660     if (qgl_context_storage.hasLocalData())
661         qgl_context_storage.localData()->context = 0;
662 #ifndef QT_MAC_USE_COCOA
663     aglSetCurrentContext(0);
664 #else
665     [NSOpenGLContext clearCurrentContext];
666 #endif
669 void QGLContext::swapBuffers() const
671     Q_D(const QGLContext);
672     if (!d->valid)
673         return;
674 #ifndef QT_MAC_USE_COCOA
675     aglSwapBuffers((AGLContext)d->cx);
676 #else
677     [static_cast<NSOpenGLContext *>(d->cx) flushBuffer];
678 #endif
681 QColor QGLContext::overlayTransparentColor() const
683     return QColor(0, 0, 0);                // Invalid color
686 #ifndef QT_MAC_USE_COCOA
687 static QColor cmap[256];
688 static bool cmap_init = false;
689 #endif
690 uint QGLContext::colorIndex(const QColor &c) const
692 #ifndef QT_MAC_USE_COCOA
693     int ret = -1;
694     if(!cmap_init) {
695         cmap_init = true;
696         for(int i = 0; i < 256; i++)
697             cmap[i] = QColor();
698     } else {
699         for(int i = 0; i < 256; i++) {
700             if(cmap[i].isValid() && cmap[i] == c) {
701                 ret = i;
702                 break;
703             }
704         }
705     }
706     if(ret == -1) {
707         for(ret = 0; ret < 256; ret++)
708             if(!cmap[ret].isValid())
709                 break;
710         if(ret == 256) {
711             ret = -1;
712             qWarning("QGLContext::colorIndex(): Internal error!");
713         } else {
714             cmap[ret] = c;
716             GLint vals[4];
717             vals[0] = ret;
718             vals[1] = c.red();
719             vals[2] = c.green();
720             vals[3] = c.blue();
721             aglSetInteger((AGLContext)d_func()->cx, AGL_COLORMAP_ENTRY, vals);
722         }
723     }
724     return (uint)(ret == -1 ? 0 : ret);
725 #else
726     Q_UNUSED(c);
727     return 0;
728 #endif
731 void QGLContext::generateFontDisplayLists(const QFont & /* fnt */, int /* listBase */)
735 static CFBundleRef qt_getOpenGLBundle()
737     CFBundleRef bundle = 0;
738     QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
739                  QCFString::toCFStringRef(QLatin1String("/System/Library/Frameworks/OpenGL.framework")), kCFURLPOSIXPathStyle, false);
740     if (url)
741         bundle = CFBundleCreate(kCFAllocatorDefault, url);
742     return bundle;
745 void *QGLContext::getProcAddress(const QString &proc) const
747     return CFBundleGetFunctionPointerForName(QCFType<CFBundleRef>(qt_getOpenGLBundle()),
748                                              QCFString(proc));
750 #ifndef QT_MAC_USE_COCOA
751 /*****************************************************************************
752   QGLWidget AGL-specific code
753  *****************************************************************************/
755 /****************************************************************************
756   Hacks to glue AGL to an HIView
757  ***************************************************************************/
758 QRegion qt_mac_get_widget_rgn(const QWidget *widget)
760     if(!widget->isVisible() || widget->isMinimized())
761         return QRegion();
762     const QRect wrect = QRect(qt_mac_posInWindow(widget), widget->size());
763     if(!wrect.isValid())
764         return QRegion();
766     RgnHandle macr = qt_mac_get_rgn();
767     GetControlRegion((HIViewRef)widget->winId(), kControlStructureMetaPart, macr);
768     OffsetRgn(macr, wrect.x(), wrect.y());
769     QRegion ret = qt_mac_convert_mac_region(macr);
771     QPoint clip_pos = wrect.topLeft();
772     for(const QWidget *last_clip = 0, *clip = widget; clip; last_clip = clip, clip = clip->parentWidget()) {
773         if(clip != widget) {
774             GetControlRegion((HIViewRef)clip->winId(), kControlStructureMetaPart, macr);
775             OffsetRgn(macr, clip_pos.x(), clip_pos.y());
776             ret &= qt_mac_convert_mac_region(macr);
777         }
778         const QObjectList &children = clip->children();
779         for(int i = children.size()-1; i >= 0; --i) {
780             if(QWidget *child = qobject_cast<QWidget*>(children.at(i))) {
781                 if(child == last_clip)
782                     break;
784                 // This check may seem weird, but when we are using a unified toolbar
785                 // The widget is actually being owned by that toolbar and not by Qt.
786                 // This means that the geometry it reports will be wrong
787                 // and will accidentally cause problems when calculating the region
788                 // So, it is better to skip these widgets since they aren't the hierarchy
789                 // anyway.
790                 if (HIViewGetSuperview(HIViewRef(child->winId())) != HIViewRef(clip->winId()))
791                     continue;
793                 if(child->isVisible() && !child->isMinimized() && !child->isTopLevel()) {
794                     const QRect childRect = QRect(clip_pos+child->pos(), child->size());
795                     if(childRect.isValid() && wrect.intersects(childRect)) {
796                         GetControlRegion((HIViewRef)child->winId(), kControlStructureMetaPart, macr);
797                         OffsetRgn(macr, childRect.x(), childRect.y());
798                         ret -= qt_mac_convert_mac_region(macr);
799                     }
800                 }
801             }
802         }
803         if(clip->isWindow())
804             break;
805         clip_pos -= clip->pos();
806     }
807     qt_mac_dispose_rgn(macr);
808     return ret;
811 #endif
813 void QGLWidget::setMouseTracking(bool enable)
815     QWidget::setMouseTracking(enable);
818 void QGLWidget::resizeEvent(QResizeEvent *)
820     Q_D(QGLWidget);
821     if (!isValid())
822         return;
823 #ifndef QT_MAC_USE_COCOA
824     if (!isWindow())
825         d->glcx->d_func()->update = true;
826 #endif
827     makeCurrent();
828     if (!d->glcx->initialized())
829         glInit();
830 #ifdef QT_MAC_USE_COCOA
831     d->glcx->updatePaintDevice();
832 #endif
833 #ifndef QT_MAC_USE_COCOA
834     float scale  = qt_mac_get_scale_factor(this);
835     resizeGL(width() * scale, height() * scale);
836 #else
837     resizeGL(width(), height());
838 #endif
841 const QGLContext* QGLWidget::overlayContext() const
843     return 0;
846 void QGLWidget::makeOverlayCurrent()
850 void QGLWidget::updateOverlayGL()
854 void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
856     Q_D(QGLWidget);
857     if (context == 0) {
858         qWarning("QGLWidget::setContext: Cannot set null context");
859         return;
860     }
862     if (d->glcx)
863         d->glcx->doneCurrent();
864     QGLContext* oldcx = d->glcx;
865     d->glcx = context;
866     if (!d->glcx->isValid())
867         d->glcx->create(shareContext ? shareContext : oldcx);
868     if (deleteOldContext && oldcx)
869         delete oldcx;
872 void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget *shareWidget)
874     Q_Q(QGLWidget);
876     initContext(context, shareWidget);
878     QWidget *current = q;
879     while (current) {
880         qt_widget_private(current)->glWidgets.append(QWidgetPrivate::GlWidgetInfo(q));
881         if (current->isWindow())
882             break;
883         current = current->parentWidget();
884     }
886     isGLWidget = 1;
889 bool QGLWidgetPrivate::renderCxPm(QPixmap*)
891     return false;
894 void QGLWidgetPrivate::cleanupColormaps()
898 const QGLColormap & QGLWidget::colormap() const
900     return d_func()->cmap;
903 void QGLWidget::setColormap(const QGLColormap &)
907 void QGLWidgetPrivate::updatePaintDevice()
909     Q_Q(QGLWidget);
910     glcx->updatePaintDevice();
911     q->update();
915 void QGLExtensions::init()
917     static bool init_done = false;
919     if (init_done)
920         return;
921     init_done = true;
923 #ifndef QT_MAC_USE_COCOA
924     GLint attribs[] = { AGL_RGBA, AGL_NONE };
925     AGLPixelFormat fmt = aglChoosePixelFormat(0, 0, attribs);
926     if (!fmt) {
927         qDebug("QGLExtensions: Couldn't find any RGB visuals");
928         return;
929     }
930     AGLContext ctx = aglCreateContext(fmt, 0);
931     if (!ctx) {
932         qDebug("QGLExtensions: Unable to create context");
933     } else {
934         aglSetCurrentContext(ctx);
935         init_extensions();
936         aglSetCurrentContext(0);
937         aglDestroyContext(ctx);
938     }
939     aglDestroyPixelFormat(fmt);
940 #else
941     QMacCocoaAutoReleasePool pool;
942     NSOpenGLPixelFormatAttribute attribs[] = { 0 };
943     NSOpenGLPixelFormat *fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
944     if (!fmt) {
945         qWarning("QGLExtensions: Cannot find any visuals");
946         return;
947     }
949     NSOpenGLContext *ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:0];
950     if (!ctx) {
951         qWarning("QGLExtensions: Cannot create context");
952     } else {
953         [ctx makeCurrentContext];
954         init_extensions();
955         [NSOpenGLContext clearCurrentContext];
956         [ctx release];
957     }
958     [fmt release];
959 #endif
962 #endif
964 QT_END_NAMESPACE