util/src/opengl/qgl_mac.mm
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qgl.h"
       
    43 
       
    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
       
    66 
       
    67 
       
    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>
       
    81 
       
    82 QT_BEGIN_NAMESPACE
       
    83 #ifdef QT_MAC_USE_COCOA
       
    84 QT_END_NAMESPACE
       
    85 
       
    86 QT_FORWARD_DECLARE_CLASS(QWidget)
       
    87 QT_FORWARD_DECLARE_CLASS(QWidgetPrivate)
       
    88 QT_FORWARD_DECLARE_CLASS(QGLWidgetPrivate)
       
    89 
       
    90 QT_BEGIN_NAMESPACE
       
    91 
       
    92 void *qt_current_nsopengl_context()
       
    93 {
       
    94     return [NSOpenGLContext currentContext];
       
    95 }
       
    96 
       
    97 static GLint attribValue(NSOpenGLPixelFormat *fmt, NSOpenGLPixelFormatAttribute attrib)
       
    98 {
       
    99     GLint res;
       
   100     [fmt getValues:&res forAttribute:attrib forVirtualScreen:0];
       
   101     return res;
       
   102 }
       
   103 
       
   104 static int def(int val, int defVal)
       
   105 {
       
   106     return val != -1 ? val : defVal;
       
   107 }
       
   108 #else
       
   109 QRegion qt_mac_get_widget_rgn(const QWidget *widget);
       
   110 #endif
       
   111 
       
   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
       
   118 
       
   119 /*
       
   120     QGLTemporaryContext implementation
       
   121 */
       
   122 
       
   123 class QGLTemporaryContextPrivate
       
   124 {
       
   125 public:
       
   126 #ifndef QT_MAC_USE_COCOA
       
   127     AGLContext ctx;
       
   128 #else
       
   129     NSOpenGLContext *ctx;
       
   130 #endif
       
   131 };
       
   132 
       
   133 QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *)
       
   134     : d(new QGLTemporaryContextPrivate)
       
   135 {
       
   136     d->ctx = 0;
       
   137 #ifndef QT_MAC_USE_COCOA
       
   138     GLint attribs[] = {AGL_RGBA, AGL_NONE};
       
   139     AGLPixelFormat fmt = aglChoosePixelFormat(0, 0, attribs);
       
   140     if (!fmt) {
       
   141         qDebug("QGLTemporaryContext: Couldn't find any RGB visuals");
       
   142         return;
       
   143     }
       
   144     d->ctx = aglCreateContext(fmt, 0);
       
   145     if (!d->ctx)
       
   146         qDebug("QGLTemporaryContext: Unable to create context");
       
   147     else
       
   148         aglSetCurrentContext(d->ctx);
       
   149     aglDestroyPixelFormat(fmt);
       
   150 #else
       
   151     QMacCocoaAutoReleasePool pool;
       
   152     NSOpenGLPixelFormatAttribute attribs[] = { 0 };
       
   153     NSOpenGLPixelFormat *fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
       
   154     if (!fmt) {
       
   155         qWarning("QGLTemporaryContext: Cannot find any visuals");
       
   156         return;
       
   157     }
       
   158 
       
   159     d->ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:0];
       
   160     if (!d->ctx)
       
   161         qWarning("QGLTemporaryContext: Cannot create context");
       
   162     else
       
   163         [d->ctx makeCurrentContext];
       
   164     [fmt release];
       
   165 #endif
       
   166 }
       
   167 
       
   168 QGLTemporaryContext::~QGLTemporaryContext()
       
   169 {
       
   170     if (d->ctx) {
       
   171 #ifndef QT_MAC_USE_COCOA
       
   172         aglSetCurrentContext(0);
       
   173         aglDestroyContext(d->ctx);
       
   174 #else
       
   175         [NSOpenGLContext clearCurrentContext];
       
   176         [d->ctx release];
       
   177 #endif
       
   178     }
       
   179 }
       
   180 
       
   181 bool QGLFormat::hasOpenGL()
       
   182 {
       
   183     return true;
       
   184 }
       
   185 
       
   186 bool QGLFormat::hasOpenGLOverlays()
       
   187 {
       
   188     return false;
       
   189 }
       
   190 
       
   191 bool QGLContext::chooseContext(const QGLContext *shareContext)
       
   192 {
       
   193     QMacCocoaAutoReleasePool pool;
       
   194     Q_D(QGLContext);
       
   195     d->cx = 0;
       
   196     d->vi = chooseMacVisual(0);
       
   197     if (!d->vi)
       
   198         return false;
       
   199 
       
   200 #ifndef QT_MAC_USE_COCOA
       
   201     AGLPixelFormat fmt = (AGLPixelFormat)d->vi;
       
   202     GLint res;
       
   203     aglDescribePixelFormat(fmt, AGL_LEVEL, &res);
       
   204     d->glFormat.setPlane(res);
       
   205     if (deviceIsPixmap())
       
   206         res = 0;
       
   207     else
       
   208         aglDescribePixelFormat(fmt, AGL_DOUBLEBUFFER, &res);
       
   209     d->glFormat.setDoubleBuffer(res);
       
   210     aglDescribePixelFormat(fmt, AGL_DEPTH_SIZE, &res);
       
   211     d->glFormat.setDepth(res);
       
   212     if (d->glFormat.depth())
       
   213         d->glFormat.setDepthBufferSize(res);
       
   214     aglDescribePixelFormat(fmt, AGL_RGBA, &res);
       
   215     d->glFormat.setRgba(res);
       
   216     aglDescribePixelFormat(fmt, AGL_RED_SIZE, &res);
       
   217     d->glFormat.setRedBufferSize(res);
       
   218     aglDescribePixelFormat(fmt, AGL_GREEN_SIZE, &res);
       
   219     d->glFormat.setGreenBufferSize(res);
       
   220     aglDescribePixelFormat(fmt, AGL_BLUE_SIZE, &res);
       
   221     d->glFormat.setBlueBufferSize(res);
       
   222     aglDescribePixelFormat(fmt, AGL_ALPHA_SIZE, &res);
       
   223     d->glFormat.setAlpha(res);
       
   224     if (d->glFormat.alpha())
       
   225         d->glFormat.setAlphaBufferSize(res);
       
   226     aglDescribePixelFormat(fmt, AGL_ACCUM_RED_SIZE, &res);
       
   227     // Bug in Apple OpenGL (rdr://5015603), when we don't have an accumulation
       
   228     // buffer, it still claims that we have a 16-bit one (which is pretty rare).
       
   229     // So, we just assume we can never have a buffer that small.
       
   230     d->glFormat.setAccum(res > 5);
       
   231     if (d->glFormat.accum())
       
   232         d->glFormat.setAccumBufferSize(res);
       
   233     aglDescribePixelFormat(fmt, AGL_STENCIL_SIZE, &res);
       
   234     d->glFormat.setStencil(res);
       
   235     if (d->glFormat.stencil())
       
   236         d->glFormat.setStencilBufferSize(res);
       
   237     aglDescribePixelFormat(fmt, AGL_STEREO, &res);
       
   238     d->glFormat.setStereo(res);
       
   239     aglDescribePixelFormat(fmt, AGL_SAMPLE_BUFFERS_ARB, &res);
       
   240     d->glFormat.setSampleBuffers(res);
       
   241     if (d->glFormat.sampleBuffers()) {
       
   242         aglDescribePixelFormat(fmt, AGL_SAMPLES_ARB, &res);
       
   243         d->glFormat.setSamples(res);
       
   244     }
       
   245 #else
       
   246     NSOpenGLPixelFormat *fmt = static_cast<NSOpenGLPixelFormat *>(d->vi);
       
   247 
       
   248     d->glFormat = QGLFormat();
       
   249 
       
   250     // ### make sure to reset other options
       
   251     d->glFormat.setDoubleBuffer(attribValue(fmt, NSOpenGLPFADoubleBuffer));
       
   252 
       
   253     int depthSize = attribValue(fmt, NSOpenGLPFADepthSize);
       
   254     d->glFormat.setDepth(depthSize > 0);
       
   255     if (depthSize > 0)
       
   256         d->glFormat.setDepthBufferSize(depthSize);
       
   257 
       
   258     int alphaSize = attribValue(fmt, NSOpenGLPFAAlphaSize);
       
   259     d->glFormat.setAlpha(alphaSize > 0);
       
   260     if (alphaSize > 0)
       
   261         d->glFormat.setAlphaBufferSize(alphaSize);
       
   262 
       
   263     int accumSize = attribValue(fmt, NSOpenGLPFAAccumSize);
       
   264     d->glFormat.setAccum(accumSize > 0);
       
   265     if (accumSize > 0)
       
   266         d->glFormat.setAccumBufferSize(accumSize);
       
   267 
       
   268     int stencilSize = attribValue(fmt, NSOpenGLPFAStencilSize);
       
   269     d->glFormat.setStencil(stencilSize > 0);
       
   270     if (stencilSize > 0)
       
   271         d->glFormat.setStencilBufferSize(stencilSize);
       
   272 
       
   273     d->glFormat.setStereo(attribValue(fmt, NSOpenGLPFAStereo));
       
   274 
       
   275     int sampleBuffers = attribValue(fmt, NSOpenGLPFASampleBuffers);
       
   276     d->glFormat.setSampleBuffers(sampleBuffers);
       
   277     if (sampleBuffers > 0)
       
   278         d->glFormat.setSamples(attribValue(fmt, NSOpenGLPFASamples));
       
   279 #endif
       
   280     if (shareContext && (!shareContext->isValid() || !shareContext->d_func()->cx)) {
       
   281         qWarning("QGLContext::chooseContext: Cannot share with invalid context");
       
   282         shareContext = 0;
       
   283     }
       
   284 
       
   285     // sharing between rgba and color-index will give wrong colors
       
   286     if (shareContext && (format().rgba() != shareContext->format().rgba()))
       
   287         shareContext = 0;
       
   288 
       
   289 #ifndef QT_MAC_USE_COCOA
       
   290     AGLContext ctx = aglCreateContext(fmt, (AGLContext) (shareContext ? shareContext->d_func()->cx : 0));
       
   291 #else
       
   292     NSOpenGLContext *ctx = [[NSOpenGLContext alloc] initWithFormat:fmt
       
   293         shareContext:(shareContext ? static_cast<NSOpenGLContext *>(shareContext->d_func()->cx)
       
   294                                    : 0)];
       
   295 #endif
       
   296     if (!ctx) {
       
   297 #ifndef QT_MAC_USE_COCOA
       
   298         GLenum err = aglGetError();
       
   299         if (err == AGL_BAD_MATCH || err == AGL_BAD_CONTEXT) {
       
   300             if (shareContext && shareContext->d_func()->cx) {
       
   301                 qWarning("QGLContext::chooseContext(): Context sharing mismatch!");
       
   302                 if (!(ctx = aglCreateContext(fmt, 0)))
       
   303                     return false;
       
   304                 shareContext = 0;
       
   305             }
       
   306         }
       
   307 #else
       
   308         if (shareContext) {
       
   309             ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:0];
       
   310             if (ctx) {
       
   311                 qWarning("QGLContext::chooseContext: Context sharing mismatch");
       
   312                 shareContext = 0;
       
   313             }
       
   314         }
       
   315 #endif
       
   316         if (!ctx) {
       
   317             qWarning("QGLContext::chooseContext: Unable to create QGLContext");
       
   318             return false;
       
   319         }
       
   320     }
       
   321     d->cx = ctx;
       
   322     if (shareContext && shareContext->d_func()->cx) {
       
   323         QGLContext *share = const_cast<QGLContext *>(shareContext);
       
   324         d->sharing = true;
       
   325         share->d_func()->sharing = true;
       
   326     }
       
   327     if (deviceIsPixmap())
       
   328         updatePaintDevice();
       
   329 
       
   330     // vblank syncing
       
   331     GLint interval = d->reqFormat.swapInterval();
       
   332     if (interval != -1) {
       
   333 #ifndef QT_MAC_USE_COCOA
       
   334         aglSetInteger((AGLContext)d->cx, AGL_SWAP_INTERVAL, &interval);
       
   335         if (interval != 0)
       
   336             aglEnable((AGLContext)d->cx, AGL_SWAP_INTERVAL);
       
   337         else
       
   338             aglDisable((AGLContext)d->cx, AGL_SWAP_INTERVAL);
       
   339 #else
       
   340         [ctx setValues:&interval forParameter:NSOpenGLCPSwapInterval];
       
   341 #endif
       
   342     }
       
   343 #ifndef QT_MAC_USE_COCOA
       
   344     aglGetInteger((AGLContext)d->cx, AGL_SWAP_INTERVAL, &interval);
       
   345 #else
       
   346     [ctx getValues:&interval forParameter:NSOpenGLCPSwapInterval];
       
   347 #endif
       
   348     d->glFormat.setSwapInterval(interval);
       
   349     return true;
       
   350 }
       
   351 
       
   352 void *QGLContextPrivate::tryFormat(const QGLFormat &format)
       
   353 {
       
   354     static const int Max = 40;
       
   355 #ifndef QT_MAC_USE_COCOA
       
   356     GLint attribs[Max], cnt = 0;
       
   357     bool device_is_pixmap = (paintDevice->devType() == QInternal::Pixmap);
       
   358 
       
   359     attribs[cnt++] = AGL_RGBA;
       
   360     attribs[cnt++] = AGL_BUFFER_SIZE;
       
   361     attribs[cnt++] = device_is_pixmap ? static_cast<QPixmap *>(paintDevice)->depth() : 32;
       
   362     attribs[cnt++] = AGL_LEVEL;
       
   363     attribs[cnt++] = format.plane();
       
   364 
       
   365     if (format.redBufferSize() != -1) {
       
   366         attribs[cnt++] = AGL_RED_SIZE;
       
   367         attribs[cnt++] = format.redBufferSize();
       
   368     }
       
   369     if (format.greenBufferSize() != -1) {
       
   370         attribs[cnt++] = AGL_GREEN_SIZE;
       
   371         attribs[cnt++] = format.greenBufferSize();
       
   372     }
       
   373     if (format.blueBufferSize() != -1) {
       
   374         attribs[cnt++] = AGL_BLUE_SIZE;
       
   375         attribs[cnt++] = format.blueBufferSize();
       
   376     }
       
   377     if (device_is_pixmap) {
       
   378         attribs[cnt++] = AGL_PIXEL_SIZE;
       
   379         attribs[cnt++] = static_cast<QPixmap *>(paintDevice)->depth();
       
   380         attribs[cnt++] = AGL_OFFSCREEN;
       
   381         if (!format.alpha()) {
       
   382             attribs[cnt++] = AGL_ALPHA_SIZE;
       
   383             attribs[cnt++] = 8;
       
   384         }
       
   385     } else {
       
   386         if (format.doubleBuffer())
       
   387             attribs[cnt++] = AGL_DOUBLEBUFFER;
       
   388     }
       
   389 
       
   390     if (format.stereo())
       
   391         attribs[cnt++] = AGL_STEREO;
       
   392     if (format.alpha()) {
       
   393         attribs[cnt++] = AGL_ALPHA_SIZE;
       
   394         attribs[cnt++] = format.alphaBufferSize() == -1 ? 8 : format.alphaBufferSize();
       
   395     }
       
   396     if (format.stencil()) {
       
   397         attribs[cnt++] = AGL_STENCIL_SIZE;
       
   398         attribs[cnt++] = format.stencilBufferSize() == -1 ? 8 : format.stencilBufferSize();
       
   399     }
       
   400     if (format.depth()) {
       
   401         attribs[cnt++] = AGL_DEPTH_SIZE;
       
   402         attribs[cnt++] = format.depthBufferSize() == -1 ? 32 : format.depthBufferSize();
       
   403     }
       
   404     if (format.accum()) {
       
   405         attribs[cnt++] = AGL_ACCUM_RED_SIZE;
       
   406         attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
       
   407         attribs[cnt++] = AGL_ACCUM_BLUE_SIZE;
       
   408         attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
       
   409         attribs[cnt++] = AGL_ACCUM_GREEN_SIZE;
       
   410         attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
       
   411         attribs[cnt++] = AGL_ACCUM_ALPHA_SIZE;
       
   412         attribs[cnt++] = format.accumBufferSize() == -1 ? 1 : format.accumBufferSize();
       
   413     }
       
   414     if (format.sampleBuffers()) {
       
   415         attribs[cnt++] = AGL_SAMPLE_BUFFERS_ARB;
       
   416         attribs[cnt++] = 1;
       
   417         attribs[cnt++] = AGL_SAMPLES_ARB;
       
   418         attribs[cnt++] = format.samples() == -1 ? 4 : format.samples();
       
   419     }
       
   420 
       
   421     attribs[cnt] = AGL_NONE;
       
   422     Q_ASSERT(cnt < Max);
       
   423     return aglChoosePixelFormat(0, 0, attribs);
       
   424 #else
       
   425     NSOpenGLPixelFormatAttribute attribs[Max];
       
   426     int cnt = 0;
       
   427     int devType = paintDevice->devType();
       
   428     bool device_is_pixmap = (devType == QInternal::Pixmap);
       
   429     int depth = device_is_pixmap ? static_cast<QPixmap *>(paintDevice)->depth() : 32;
       
   430 
       
   431     attribs[cnt++] = NSOpenGLPFAColorSize;
       
   432     attribs[cnt++] = depth;
       
   433 
       
   434     if (device_is_pixmap) {
       
   435         attribs[cnt++] = NSOpenGLPFAOffScreen;
       
   436     } else {
       
   437         if (format.doubleBuffer())
       
   438             attribs[cnt++] = NSOpenGLPFADoubleBuffer;
       
   439     }
       
   440     if (glFormat.stereo())
       
   441         attribs[cnt++] = NSOpenGLPFAStereo;
       
   442     if (device_is_pixmap || format.alpha()) {
       
   443         attribs[cnt++] = NSOpenGLPFAAlphaSize;
       
   444         attribs[cnt++] = def(format.alphaBufferSize(), 8);
       
   445     }
       
   446     if (format.stencil()) {
       
   447         attribs[cnt++] = NSOpenGLPFAStencilSize;
       
   448         attribs[cnt++] = def(format.stencilBufferSize(), 8);
       
   449     }
       
   450     if (format.depth()) {
       
   451         attribs[cnt++] = NSOpenGLPFADepthSize;
       
   452         attribs[cnt++] = def(format.depthBufferSize(), 32);
       
   453     }
       
   454     if (format.accum()) {
       
   455         attribs[cnt++] = NSOpenGLPFAAccumSize;
       
   456         attribs[cnt++] = def(format.accumBufferSize(), 1);
       
   457     }
       
   458     if (format.sampleBuffers()) {
       
   459         attribs[cnt++] = NSOpenGLPFASampleBuffers;
       
   460         attribs[cnt++] = 1;
       
   461         attribs[cnt++] = NSOpenGLPFASamples;
       
   462         attribs[cnt++] = def(format.samples(), 4);
       
   463     }
       
   464 
       
   465     if (format.directRendering())
       
   466         attribs[cnt++] = NSOpenGLPFAAccelerated;
       
   467 
       
   468     if (devType == QInternal::Pbuffer)
       
   469         attribs[cnt++] = NSOpenGLPFAPixelBuffer;
       
   470 
       
   471     attribs[cnt] = 0;
       
   472     Q_ASSERT(cnt < Max);
       
   473     return [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
       
   474 #endif
       
   475 }
       
   476 
       
   477 void QGLContextPrivate::clearDrawable()
       
   478 {
       
   479     [static_cast<NSOpenGLContext *>(cx) clearDrawable];
       
   480 }
       
   481 
       
   482 /*!
       
   483     \bold{Mac OS X only:} This virtual function tries to find a visual that
       
   484     matches the format, reducing the demands if the original request
       
   485     cannot be met.
       
   486 
       
   487     The algorithm for reducing the demands of the format is quite
       
   488     simple-minded, so override this method in your subclass if your
       
   489     application has spcific requirements on visual selection.
       
   490 
       
   491     The \a handle argument is always zero and is not used
       
   492 
       
   493     \sa chooseContext()
       
   494 */
       
   495 
       
   496 void *QGLContext::chooseMacVisual(GDHandle /* handle */)
       
   497 {
       
   498     Q_D(QGLContext);
       
   499 
       
   500     void *fmt = d->tryFormat(d->glFormat);
       
   501     if (!fmt && d->glFormat.stereo()) {
       
   502         d->glFormat.setStereo(false);
       
   503         fmt = d->tryFormat(d->glFormat);
       
   504     }
       
   505     if (!fmt && d->glFormat.sampleBuffers()) {
       
   506         d->glFormat.setSampleBuffers(false);
       
   507         fmt = d->tryFormat(d->glFormat);
       
   508     }
       
   509     if (!fmt)
       
   510         qWarning("QGLContext::chooseMacVisual: Unable to choose a pixel format");
       
   511     return fmt;
       
   512 }
       
   513 
       
   514 void QGLContext::reset()
       
   515 {
       
   516     Q_D(QGLContext);
       
   517     if (!d->valid)
       
   518         return;
       
   519     d->cleanup();
       
   520     doneCurrent();
       
   521 #ifndef QT_MAC_USE_COCOA
       
   522     if (d->cx)
       
   523         aglDestroyContext((AGLContext)d->cx);
       
   524 #else
       
   525     QMacCocoaAutoReleasePool pool;
       
   526     [static_cast<NSOpenGLContext *>(d->cx) release];
       
   527 #endif
       
   528     d->cx = 0;
       
   529 #ifndef QT_MAC_USE_COCOA
       
   530     if (d->vi)
       
   531         aglDestroyPixelFormat((AGLPixelFormat)d->vi);
       
   532 #else
       
   533     [static_cast<NSOpenGLPixelFormat *>(d->vi) release];
       
   534 #endif
       
   535     d->vi = 0;
       
   536     d->crWin = false;
       
   537     d->sharing = false;
       
   538     d->valid = false;
       
   539     d->transpColor = QColor();
       
   540     d->initDone = false;
       
   541     QGLContextGroup::removeShare(this);
       
   542 }
       
   543 
       
   544 void QGLContext::makeCurrent()
       
   545 {
       
   546     Q_D(QGLContext);
       
   547 
       
   548     if (!d->valid) {
       
   549         qWarning("QGLContext::makeCurrent: Cannot make invalid context current");
       
   550         return;
       
   551     }
       
   552 #ifndef QT_MAC_USE_COCOA
       
   553     aglSetCurrentContext((AGLContext)d->cx);
       
   554     if (d->update)
       
   555         updatePaintDevice();
       
   556 #else
       
   557     [static_cast<NSOpenGLContext *>(d->cx) makeCurrentContext];
       
   558 #endif
       
   559     QGLContextPrivate::setCurrentContext(this);
       
   560 }
       
   561 
       
   562 #ifndef QT_MAC_USE_COCOA
       
   563 /*
       
   564     Returns the effective scale factor for a widget. For this value to be
       
   565     different than 1, the following must be true:
       
   566     - The system scale factor must be greater than 1.
       
   567     - The widget window must have WA_MacFrameworkScaled set.
       
   568 */
       
   569 float qt_mac_get_scale_factor(QWidget *widget)
       
   570 {
       
   571     if (!widget | !widget->window())
       
   572         return 1;
       
   573 
       
   574     if (widget->window()->testAttribute(Qt::WA_MacFrameworkScaled) == false)
       
   575         return 1;
       
   576 
       
   577     float systemScale = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4 ? HIGetScaleFactor() : 1;
       
   578     if (systemScale == float(1))
       
   579         return 1;
       
   580 
       
   581     return systemScale;
       
   582 }
       
   583 #endif
       
   584 
       
   585 /*! \internal
       
   586 */
       
   587 void QGLContext::updatePaintDevice()
       
   588 {
       
   589     Q_D(QGLContext);
       
   590 #ifndef QT_MAC_USE_COCOA
       
   591     d->update = false;
       
   592     if (d->paintDevice->devType() == QInternal::Widget) {
       
   593         //get control information
       
   594         QWidget *w = (QWidget *)d->paintDevice;
       
   595         HIViewRef hiview = (HIViewRef)w->winId();
       
   596         WindowRef window = HIViewGetWindow(hiview);
       
   597 #ifdef DEBUG_OPENGL_REGION_UPDATE
       
   598         static int serial_no_gl = 0;
       
   599         qDebug("[%d] %p setting on %s::%s %p/%p [%s]", ++serial_no_gl, w,
       
   600                 w->metaObject()->className(), w->objectName().toLatin1().constData(),
       
   601                 hiview, window, w->handle() ? "Inside" : "Outside");
       
   602 #endif
       
   603 
       
   604         //update drawable
       
   605         if (0 && w->isWindow() && w->isFullScreen()) {
       
   606             aglSetDrawable((AGLContext)d->cx, 0);
       
   607             aglSetFullScreen((AGLContext)d->cx, w->width(), w->height(), 0, QApplication::desktop()->screenNumber(w));
       
   608             w->hide();
       
   609         } else {
       
   610             AGLDrawable old_draw = aglGetDrawable((AGLContext)d->cx), new_draw = GetWindowPort(window);
       
   611             if (old_draw != new_draw)
       
   612                 aglSetDrawable((AGLContext)d->cx, new_draw);
       
   613         }
       
   614 
       
   615         float scale  = qt_mac_get_scale_factor(w);
       
   616 
       
   617         if (!w->isWindow()) {
       
   618             QRegion clp = qt_mac_get_widget_rgn(w); //get drawable area
       
   619 
       
   620 #ifdef DEBUG_OPENGL_REGION_UPDATE
       
   621             if (clp.isEmpty()) {
       
   622                 qDebug("  Empty area!");
       
   623             } else {
       
   624                 QVector<QRect> rs = clp.rects();
       
   625                 for(int i = 0; i < rs.count(); i++)
       
   626                     qDebug("  %d %d %d %d", rs[i].x(), rs[i].y(), rs[i].width(), rs[i].height());
       
   627             }
       
   628 #endif
       
   629             //update the clip
       
   630             if (!aglIsEnabled((AGLContext)d->cx, AGL_BUFFER_RECT))
       
   631                 aglEnable((AGLContext)d->cx, AGL_BUFFER_RECT);
       
   632             if (clp.isEmpty()) {
       
   633                 GLint offs[4] = { 0, 0, 0, 0 };
       
   634                 aglSetInteger((AGLContext)d->cx, AGL_BUFFER_RECT, offs);
       
   635                 if (aglIsEnabled((AGLContext)d->cx, AGL_CLIP_REGION))
       
   636                     aglDisable((AGLContext)d->cx, AGL_CLIP_REGION);
       
   637             } else {
       
   638                 HIPoint origin = { 0., 0. };
       
   639                 HIViewConvertPoint(&origin, HIViewRef(w->winId()), 0);
       
   640                 const GLint offs[4] = { qRound(origin.x),
       
   641                     w->window()->frameGeometry().height() * scale
       
   642                         - (qRound(origin.y) + w->height() * scale),
       
   643                     w->width() * scale, w->height() * scale};
       
   644 
       
   645                 RgnHandle region = clp.handle(true);
       
   646 
       
   647                 if (scale != float(1)) {
       
   648                     // Sacle the clip region by the scale factor
       
   649                     Rect regionBounds;
       
   650                     GetRegionBounds(region, &regionBounds);
       
   651                     Rect regionBoundsDest = regionBounds;
       
   652                     regionBoundsDest.bottom *= scale;
       
   653                     regionBoundsDest.right *= scale;
       
   654                     MapRgn(region, &regionBounds, &regionBoundsDest);
       
   655                 }
       
   656 
       
   657                 aglSetInteger((AGLContext)d->cx, AGL_BUFFER_RECT, offs);
       
   658                 aglSetInteger((AGLContext)d->cx, AGL_CLIP_REGION, (const GLint *)region);
       
   659                 if (!aglIsEnabled((AGLContext)d->cx, AGL_CLIP_REGION))
       
   660                     aglEnable((AGLContext)d->cx, AGL_CLIP_REGION);
       
   661             }
       
   662         } else {
       
   663             // Set the buffer rect for top-level gl contexts when scaled.
       
   664             if (scale != float(1)) {
       
   665                 aglEnable((AGLContext)d->cx, AGL_BUFFER_RECT);
       
   666                 const GLint offs[4] = { 0, 0,  w->width() * scale , w->height() * scale};
       
   667                 aglSetInteger((AGLContext)d->cx, AGL_BUFFER_RECT, offs);
       
   668             }
       
   669         }
       
   670     } else if (d->paintDevice->devType() == QInternal::Pixmap) {
       
   671         QPixmap *pm = reinterpret_cast<QPixmap *>(d->paintDevice);
       
   672 
       
   673         unsigned long qdformat = k32ARGBPixelFormat;
       
   674         if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)
       
   675             qdformat = k32BGRAPixelFormat;
       
   676         Rect rect;
       
   677         SetRect(&rect, 0, 0, pm->width(), pm->height());
       
   678 
       
   679         GWorldPtr gworld;
       
   680         NewGWorldFromPtr(&gworld, qdformat, &rect, 0, 0, 0,
       
   681                          reinterpret_cast<char *>(qt_mac_pixmap_get_base(pm)), 
       
   682                          qt_mac_pixmap_get_bytes_per_line(pm));
       
   683 
       
   684         PixMapHandle pixmapHandle = GetGWorldPixMap(gworld);
       
   685         aglSetOffScreen(reinterpret_cast<AGLContext>(d->cx), pm->width(), pm->height(),
       
   686                         GetPixRowBytes(pixmapHandle), GetPixBaseAddr(pixmapHandle));
       
   687     } else {
       
   688         qWarning("QGLContext::updatePaintDevice(): Not sure how to render OpenGL on this device!");
       
   689     }
       
   690     aglUpdateContext((AGLContext)d->cx);
       
   691 
       
   692 #else
       
   693     QMacCocoaAutoReleasePool pool;
       
   694 
       
   695     if (d->paintDevice->devType() == QInternal::Widget) {
       
   696         //get control information
       
   697         QWidget *w = (QWidget *)d->paintDevice;
       
   698         NSView *view = qt_mac_nativeview_for(w);
       
   699 
       
   700         // ideally we would use QWidget::isVisible(), but we get "invalid drawable" errors
       
   701         if (![(NSWindow *)qt_mac_window_for(w) isVisible])
       
   702             return;
       
   703         if ([static_cast<NSOpenGLContext *>(d->cx) view] != view && ![view isHidden])
       
   704             [static_cast<NSOpenGLContext *>(d->cx) setView:view];
       
   705     } else if (d->paintDevice->devType() == QInternal::Pixmap) {
       
   706         const QPixmap *pm = static_cast<const QPixmap *>(d->paintDevice);
       
   707         [static_cast<NSOpenGLContext *>(d->cx) setOffScreen:qt_mac_pixmap_get_base(pm)
       
   708                                                       width:pm->width()
       
   709                                                      height:pm->height()
       
   710                                                    rowbytes:qt_mac_pixmap_get_bytes_per_line(pm)];
       
   711     } else {
       
   712         qWarning("QGLContext::updatePaintDevice: Not sure how to render OpenGL on this device");
       
   713     }
       
   714     [static_cast<NSOpenGLContext *>(d->cx) update];
       
   715 #endif
       
   716 }
       
   717 
       
   718 void QGLContext::doneCurrent()
       
   719 {
       
   720 
       
   721     if (
       
   722 #ifndef QT_MAC_USE_COCOA
       
   723         aglGetCurrentContext() != (AGLContext) d_func()->cx
       
   724 #else
       
   725         [NSOpenGLContext currentContext] != d_func()->cx
       
   726 #endif
       
   727        )
       
   728         return;
       
   729 
       
   730     QGLContextPrivate::setCurrentContext(0);
       
   731 #ifndef QT_MAC_USE_COCOA
       
   732     aglSetCurrentContext(0);
       
   733 #else
       
   734     [NSOpenGLContext clearCurrentContext];
       
   735 #endif
       
   736 }
       
   737 
       
   738 void QGLContext::swapBuffers() const
       
   739 {
       
   740     Q_D(const QGLContext);
       
   741     if (!d->valid)
       
   742         return;
       
   743 #ifndef QT_MAC_USE_COCOA
       
   744     aglSwapBuffers((AGLContext)d->cx);
       
   745 #else
       
   746     [static_cast<NSOpenGLContext *>(d->cx) flushBuffer];
       
   747 #endif
       
   748 }
       
   749 
       
   750 QColor QGLContext::overlayTransparentColor() const
       
   751 {
       
   752     return QColor(0, 0, 0);                // Invalid color
       
   753 }
       
   754 
       
   755 #ifndef QT_MAC_USE_COCOA
       
   756 static QColor cmap[256];
       
   757 static bool cmap_init = false;
       
   758 #endif
       
   759 uint QGLContext::colorIndex(const QColor &c) const
       
   760 {
       
   761 #ifndef QT_MAC_USE_COCOA
       
   762     int ret = -1;
       
   763     if(!cmap_init) {
       
   764         cmap_init = true;
       
   765         for(int i = 0; i < 256; i++)
       
   766             cmap[i] = QColor();
       
   767     } else {
       
   768         for(int i = 0; i < 256; i++) {
       
   769             if(cmap[i].isValid() && cmap[i] == c) {
       
   770                 ret = i;
       
   771                 break;
       
   772             }
       
   773         }
       
   774     }
       
   775     if(ret == -1) {
       
   776         for(ret = 0; ret < 256; ret++)
       
   777             if(!cmap[ret].isValid())
       
   778                 break;
       
   779         if(ret == 256) {
       
   780             ret = -1;
       
   781             qWarning("QGLContext::colorIndex(): Internal error!");
       
   782         } else {
       
   783             cmap[ret] = c;
       
   784 
       
   785             GLint vals[4];
       
   786             vals[0] = ret;
       
   787             vals[1] = c.red();
       
   788             vals[2] = c.green();
       
   789             vals[3] = c.blue();
       
   790             aglSetInteger((AGLContext)d_func()->cx, AGL_COLORMAP_ENTRY, vals);
       
   791         }
       
   792     }
       
   793     return (uint)(ret == -1 ? 0 : ret);
       
   794 #else
       
   795     Q_UNUSED(c);
       
   796     return 0;
       
   797 #endif
       
   798 }
       
   799 
       
   800 void QGLContext::generateFontDisplayLists(const QFont & /* fnt */, int /* listBase */)
       
   801 {
       
   802 }
       
   803 
       
   804 static CFBundleRef qt_getOpenGLBundle()
       
   805 {
       
   806     CFBundleRef bundle = 0;
       
   807     QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
       
   808                  QCFString::toCFStringRef(QLatin1String("/System/Library/Frameworks/OpenGL.framework")), kCFURLPOSIXPathStyle, false);
       
   809     if (url)
       
   810         bundle = CFBundleCreate(kCFAllocatorDefault, url);
       
   811     return bundle;
       
   812 }
       
   813 
       
   814 void *QGLContext::getProcAddress(const QString &proc) const
       
   815 {
       
   816     return CFBundleGetFunctionPointerForName(QCFType<CFBundleRef>(qt_getOpenGLBundle()),
       
   817                                              QCFString(proc));
       
   818 }
       
   819 #ifndef QT_MAC_USE_COCOA
       
   820 /*****************************************************************************
       
   821   QGLWidget AGL-specific code
       
   822  *****************************************************************************/
       
   823 
       
   824 /****************************************************************************
       
   825   Hacks to glue AGL to an HIView
       
   826  ***************************************************************************/
       
   827 QRegion qt_mac_get_widget_rgn(const QWidget *widget)
       
   828 {
       
   829     if(!widget->isVisible() || widget->isMinimized())
       
   830         return QRegion();
       
   831     const QRect wrect = QRect(qt_mac_posInWindow(widget), widget->size());
       
   832     if(!wrect.isValid())
       
   833         return QRegion();
       
   834 
       
   835     RgnHandle macr = qt_mac_get_rgn();
       
   836     GetControlRegion((HIViewRef)widget->winId(), kControlStructureMetaPart, macr);
       
   837     OffsetRgn(macr, wrect.x(), wrect.y());
       
   838     QRegion ret = qt_mac_convert_mac_region(macr);
       
   839 
       
   840     QPoint clip_pos = wrect.topLeft();
       
   841     for(const QWidget *last_clip = 0, *clip = widget; clip; last_clip = clip, clip = clip->parentWidget()) {
       
   842         if(clip != widget) {
       
   843             GetControlRegion((HIViewRef)clip->winId(), kControlStructureMetaPart, macr);
       
   844             OffsetRgn(macr, clip_pos.x(), clip_pos.y());
       
   845             ret &= qt_mac_convert_mac_region(macr);
       
   846         }
       
   847         const QObjectList &children = clip->children();
       
   848         for(int i = children.size()-1; i >= 0; --i) {
       
   849             if(QWidget *child = qobject_cast<QWidget*>(children.at(i))) {
       
   850                 if(child == last_clip)
       
   851                     break;
       
   852 
       
   853                 // This check may seem weird, but when we are using a unified toolbar
       
   854                 // The widget is actually being owned by that toolbar and not by Qt.
       
   855                 // This means that the geometry it reports will be wrong
       
   856                 // and will accidentally cause problems when calculating the region
       
   857                 // So, it is better to skip these widgets since they aren't the hierarchy
       
   858                 // anyway.
       
   859                 if (HIViewGetSuperview(HIViewRef(child->winId())) != HIViewRef(clip->winId()))
       
   860                     continue;
       
   861 
       
   862                 if(child->isVisible() && !child->isMinimized() && !child->isTopLevel()) {
       
   863                     const QRect childRect = QRect(clip_pos+child->pos(), child->size());
       
   864                     if(childRect.isValid() && wrect.intersects(childRect)) {
       
   865                         GetControlRegion((HIViewRef)child->winId(), kControlStructureMetaPart, macr);
       
   866                         OffsetRgn(macr, childRect.x(), childRect.y());
       
   867                         ret -= qt_mac_convert_mac_region(macr);
       
   868                     }
       
   869                 }
       
   870             }
       
   871         }
       
   872         if(clip->isWindow())
       
   873             break;
       
   874         clip_pos -= clip->pos();
       
   875     }
       
   876     qt_mac_dispose_rgn(macr);
       
   877     return ret;
       
   878 }
       
   879 
       
   880 #endif
       
   881 
       
   882 void QGLWidget::setMouseTracking(bool enable)
       
   883 {
       
   884     QWidget::setMouseTracking(enable);
       
   885 }
       
   886 
       
   887 void QGLWidget::resizeEvent(QResizeEvent *)
       
   888 {
       
   889     Q_D(QGLWidget);
       
   890     if (!isValid())
       
   891         return;
       
   892 #ifndef QT_MAC_USE_COCOA
       
   893     if (!isWindow())
       
   894         d->glcx->d_func()->update = true;
       
   895 #endif
       
   896     makeCurrent();
       
   897     if (!d->glcx->initialized())
       
   898         glInit();
       
   899 #ifdef QT_MAC_USE_COCOA
       
   900     d->glcx->updatePaintDevice();
       
   901 #endif
       
   902 #ifndef QT_MAC_USE_COCOA
       
   903     float scale  = qt_mac_get_scale_factor(this);
       
   904     resizeGL(width() * scale, height() * scale);
       
   905 #else
       
   906     resizeGL(width(), height());
       
   907 #endif
       
   908 }
       
   909 
       
   910 const QGLContext* QGLWidget::overlayContext() const
       
   911 {
       
   912     return 0;
       
   913 }
       
   914 
       
   915 void QGLWidget::makeOverlayCurrent()
       
   916 {
       
   917 }
       
   918 
       
   919 void QGLWidget::updateOverlayGL()
       
   920 {
       
   921 }
       
   922 
       
   923 void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
       
   924 {
       
   925     Q_D(QGLWidget);
       
   926     if (context == 0) {
       
   927         qWarning("QGLWidget::setContext: Cannot set null context");
       
   928         return;
       
   929     }
       
   930 
       
   931     if (d->glcx)
       
   932         d->glcx->doneCurrent();
       
   933     QGLContext* oldcx = d->glcx;
       
   934     d->glcx = context;
       
   935     if (!d->glcx->isValid())
       
   936         d->glcx->create(shareContext ? shareContext : oldcx);
       
   937     if (deleteOldContext && oldcx)
       
   938         delete oldcx;
       
   939 }
       
   940 
       
   941 void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget *shareWidget)
       
   942 {
       
   943     Q_Q(QGLWidget);
       
   944 
       
   945     initContext(context, shareWidget);
       
   946 
       
   947     QWidget *current = q;
       
   948     while (current) {
       
   949         qt_widget_private(current)->glWidgets.append(QWidgetPrivate::GlWidgetInfo(q));
       
   950         if (current->isWindow())
       
   951             break;
       
   952         current = current->parentWidget();
       
   953     }
       
   954 }
       
   955 
       
   956 bool QGLWidgetPrivate::renderCxPm(QPixmap*)
       
   957 {
       
   958     return false;
       
   959 }
       
   960 
       
   961 void QGLWidgetPrivate::cleanupColormaps()
       
   962 {
       
   963 }
       
   964 
       
   965 const QGLColormap & QGLWidget::colormap() const
       
   966 {
       
   967     return d_func()->cmap;
       
   968 }
       
   969 
       
   970 void QGLWidget::setColormap(const QGLColormap &)
       
   971 {
       
   972 }
       
   973 
       
   974 void QGLWidgetPrivate::updatePaintDevice()
       
   975 {
       
   976     Q_Q(QGLWidget);
       
   977     glcx->updatePaintDevice();
       
   978     q->update();
       
   979 }
       
   980 
       
   981 #endif
       
   982 
       
   983 QT_END_NAMESPACE