src/opengl/qgl_mac.mm
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 bool QGLFormat::hasOpenGL()
       
   120 {
       
   121     return true;
       
   122 }
       
   123 
       
   124 bool QGLFormat::hasOpenGLOverlays()
       
   125 {
       
   126     return false;
       
   127 }
       
   128 
       
   129 bool QGLContext::chooseContext(const QGLContext *shareContext)
       
   130 {
       
   131     QMacCocoaAutoReleasePool pool;
       
   132     Q_D(QGLContext);
       
   133     d->cx = 0;
       
   134     d->vi = chooseMacVisual(0);
       
   135     if (!d->vi)
       
   136         return false;
       
   137 
       
   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);
       
   185 
       
   186     d->glFormat = QGLFormat();
       
   187 
       
   188     // ### make sure to reset other options
       
   189     d->glFormat.setDoubleBuffer(attribValue(fmt, NSOpenGLPFADoubleBuffer));
       
   190 
       
   191     int depthSize = attribValue(fmt, NSOpenGLPFADepthSize);
       
   192     d->glFormat.setDepth(depthSize > 0);
       
   193     if (depthSize > 0)
       
   194         d->glFormat.setDepthBufferSize(depthSize);
       
   195 
       
   196     int alphaSize = attribValue(fmt, NSOpenGLPFAAlphaSize);
       
   197     d->glFormat.setAlpha(alphaSize > 0);
       
   198     if (alphaSize > 0)
       
   199         d->glFormat.setAlphaBufferSize(alphaSize);
       
   200 
       
   201     int accumSize = attribValue(fmt, NSOpenGLPFAAccumSize);
       
   202     d->glFormat.setAccum(accumSize > 0);
       
   203     if (accumSize > 0)
       
   204         d->glFormat.setAccumBufferSize(accumSize);
       
   205 
       
   206     int stencilSize = attribValue(fmt, NSOpenGLPFAStencilSize);
       
   207     d->glFormat.setStencil(stencilSize > 0);
       
   208     if (stencilSize > 0)
       
   209         d->glFormat.setStencilBufferSize(stencilSize);
       
   210 
       
   211     d->glFormat.setStereo(attribValue(fmt, NSOpenGLPFAStereo));
       
   212 
       
   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     }
       
   222 
       
   223     // sharing between rgba and color-index will give wrong colors
       
   224     if (shareContext && (format().rgba() != shareContext->format().rgba()))
       
   225         shareContext = 0;
       
   226 
       
   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();
       
   267 
       
   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;
       
   288 }
       
   289 
       
   290 void *QGLContextPrivate::tryFormat(const QGLFormat &format)
       
   291 {
       
   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);
       
   296 
       
   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();
       
   302 
       
   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     }
       
   327 
       
   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     }
       
   358 
       
   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;
       
   368 
       
   369     attribs[cnt++] = NSOpenGLPFAColorSize;
       
   370     attribs[cnt++] = depth;
       
   371 
       
   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     }
       
   402 
       
   403     if (format.directRendering())
       
   404         attribs[cnt++] = NSOpenGLPFAAccelerated;
       
   405 
       
   406     if (devType == QInternal::Pbuffer)
       
   407         attribs[cnt++] = NSOpenGLPFAPixelBuffer;
       
   408 
       
   409     attribs[cnt] = 0;
       
   410     Q_ASSERT(cnt < Max);
       
   411     return [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
       
   412 #endif
       
   413 }
       
   414 
       
   415 void QGLContextPrivate::clearDrawable()
       
   416 {
       
   417     [static_cast<NSOpenGLContext *>(cx) clearDrawable];
       
   418 }
       
   419 
       
   420 /*!
       
   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.
       
   424 
       
   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.
       
   428 
       
   429     The \a handle argument is always zero and is not used
       
   430 
       
   431     \sa chooseContext()
       
   432 */
       
   433 
       
   434 void *QGLContext::chooseMacVisual(GDHandle /* handle */)
       
   435 {
       
   436     Q_D(QGLContext);
       
   437 
       
   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;
       
   450 }
       
   451 
       
   452 void QGLContext::reset()
       
   453 {
       
   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);
       
   479 }
       
   480 
       
   481 void QGLContext::makeCurrent()
       
   482 {
       
   483     Q_D(QGLContext);
       
   484 
       
   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     QGLContextPrivate::setCurrentContext(this);
       
   497 }
       
   498 
       
   499 #ifndef QT_MAC_USE_COCOA
       
   500 /*
       
   501     Returns the effective scale factor for a widget. For this value to be
       
   502     different than 1, the following must be true:
       
   503     - The system scale factor must be greater than 1.
       
   504     - The widget window must have WA_MacFrameworkScaled set.
       
   505 */
       
   506 float qt_mac_get_scale_factor(QWidget *widget)
       
   507 {
       
   508     if (!widget | !widget->window())
       
   509         return 1;
       
   510 
       
   511     if (widget->window()->testAttribute(Qt::WA_MacFrameworkScaled) == false)
       
   512         return 1;
       
   513 
       
   514     float systemScale = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4 ? HIGetScaleFactor() : 1;
       
   515     if (systemScale == float(1))
       
   516         return 1;
       
   517 
       
   518     return systemScale;
       
   519 }
       
   520 #endif
       
   521 
       
   522 /*! \internal
       
   523 */
       
   524 void QGLContext::updatePaintDevice()
       
   525 {
       
   526     Q_D(QGLContext);
       
   527 #ifndef QT_MAC_USE_COCOA
       
   528     d->update = false;
       
   529     if (d->paintDevice->devType() == QInternal::Widget) {
       
   530         //get control information
       
   531         QWidget *w = (QWidget *)d->paintDevice;
       
   532         HIViewRef hiview = (HIViewRef)w->winId();
       
   533         WindowRef window = HIViewGetWindow(hiview);
       
   534 #ifdef DEBUG_OPENGL_REGION_UPDATE
       
   535         static int serial_no_gl = 0;
       
   536         qDebug("[%d] %p setting on %s::%s %p/%p [%s]", ++serial_no_gl, w,
       
   537                 w->metaObject()->className(), w->objectName().toLatin1().constData(),
       
   538                 hiview, window, w->handle() ? "Inside" : "Outside");
       
   539 #endif
       
   540 
       
   541         //update drawable
       
   542         if (0 && w->isWindow() && w->isFullScreen()) {
       
   543             aglSetDrawable((AGLContext)d->cx, 0);
       
   544             aglSetFullScreen((AGLContext)d->cx, w->width(), w->height(), 0, QApplication::desktop()->screenNumber(w));
       
   545             w->hide();
       
   546         } else {
       
   547             AGLDrawable old_draw = aglGetDrawable((AGLContext)d->cx), new_draw = GetWindowPort(window);
       
   548             if (old_draw != new_draw)
       
   549                 aglSetDrawable((AGLContext)d->cx, new_draw);
       
   550         }
       
   551 
       
   552         float scale  = qt_mac_get_scale_factor(w);
       
   553 
       
   554         if (!w->isWindow()) {
       
   555             QRegion clp = qt_mac_get_widget_rgn(w); //get drawable area
       
   556 
       
   557 #ifdef DEBUG_OPENGL_REGION_UPDATE
       
   558             if (clp.isEmpty()) {
       
   559                 qDebug("  Empty area!");
       
   560             } else {
       
   561                 QVector<QRect> rs = clp.rects();
       
   562                 for(int i = 0; i < rs.count(); i++)
       
   563                     qDebug("  %d %d %d %d", rs[i].x(), rs[i].y(), rs[i].width(), rs[i].height());
       
   564             }
       
   565 #endif
       
   566             //update the clip
       
   567             if (!aglIsEnabled((AGLContext)d->cx, AGL_BUFFER_RECT))
       
   568                 aglEnable((AGLContext)d->cx, AGL_BUFFER_RECT);
       
   569             if (clp.isEmpty()) {
       
   570                 GLint offs[4] = { 0, 0, 0, 0 };
       
   571                 aglSetInteger((AGLContext)d->cx, AGL_BUFFER_RECT, offs);
       
   572                 if (aglIsEnabled((AGLContext)d->cx, AGL_CLIP_REGION))
       
   573                     aglDisable((AGLContext)d->cx, AGL_CLIP_REGION);
       
   574             } else {
       
   575                 HIPoint origin = { 0., 0. };
       
   576                 HIViewConvertPoint(&origin, HIViewRef(w->winId()), 0);
       
   577                 const GLint offs[4] = { qRound(origin.x),
       
   578                     w->window()->frameGeometry().height() * scale
       
   579                         - (qRound(origin.y) + w->height() * scale),
       
   580                     w->width() * scale, w->height() * scale};
       
   581 
       
   582                 RgnHandle region = clp.handle(true);
       
   583 
       
   584                 if (scale != float(1)) {
       
   585                     // Sacle the clip region by the scale factor
       
   586                     Rect regionBounds;
       
   587                     GetRegionBounds(region, &regionBounds);
       
   588                     Rect regionBoundsDest = regionBounds;
       
   589                     regionBoundsDest.bottom *= scale;
       
   590                     regionBoundsDest.right *= scale;
       
   591                     MapRgn(region, &regionBounds, &regionBoundsDest);
       
   592                 }
       
   593 
       
   594                 aglSetInteger((AGLContext)d->cx, AGL_BUFFER_RECT, offs);
       
   595                 aglSetInteger((AGLContext)d->cx, AGL_CLIP_REGION, (const GLint *)region);
       
   596                 if (!aglIsEnabled((AGLContext)d->cx, AGL_CLIP_REGION))
       
   597                     aglEnable((AGLContext)d->cx, AGL_CLIP_REGION);
       
   598             }
       
   599         } else {
       
   600             // Set the buffer rect for top-level gl contexts when scaled.
       
   601             if (scale != float(1)) {
       
   602                 aglEnable((AGLContext)d->cx, AGL_BUFFER_RECT);
       
   603                 const GLint offs[4] = { 0, 0,  w->width() * scale , w->height() * scale};
       
   604                 aglSetInteger((AGLContext)d->cx, AGL_BUFFER_RECT, offs);
       
   605             }
       
   606         }
       
   607     } else if (d->paintDevice->devType() == QInternal::Pixmap) {
       
   608         QPixmap *pm = (QPixmap *)d->paintDevice;
       
   609         PixMapHandle mac_pm = GetGWorldPixMap((GWorldPtr)pm->macQDHandle());
       
   610         aglSetOffScreen((AGLContext)d->cx, pm->width(), pm->height(),
       
   611                 GetPixRowBytes(mac_pm), GetPixBaseAddr(mac_pm));
       
   612     } else {
       
   613         qWarning("QGLContext::updatePaintDevice(): Not sure how to render OpenGL on this device!");
       
   614     }
       
   615     aglUpdateContext((AGLContext)d->cx);
       
   616 
       
   617 #else
       
   618     QMacCocoaAutoReleasePool pool;
       
   619 
       
   620     if (d->paintDevice->devType() == QInternal::Widget) {
       
   621         //get control information
       
   622         QWidget *w = (QWidget *)d->paintDevice;
       
   623         NSView *view = qt_mac_nativeview_for(w);
       
   624 
       
   625         // ideally we would use QWidget::isVisible(), but we get "invalid drawable" errors
       
   626         if (![(NSWindow *)qt_mac_window_for(w) isVisible])
       
   627             return;
       
   628         if ([static_cast<NSOpenGLContext *>(d->cx) view] != view && ![view isHidden])
       
   629             [static_cast<NSOpenGLContext *>(d->cx) setView:view];
       
   630     } else if (d->paintDevice->devType() == QInternal::Pixmap) {
       
   631         const QPixmap *pm = static_cast<const QPixmap *>(d->paintDevice);
       
   632         [static_cast<NSOpenGLContext *>(d->cx) setOffScreen:qt_mac_pixmap_get_base(pm)
       
   633                                                       width:pm->width()
       
   634                                                      height:pm->height()
       
   635                                                    rowbytes:qt_mac_pixmap_get_bytes_per_line(pm)];
       
   636     } else {
       
   637         qWarning("QGLContext::updatePaintDevice: Not sure how to render OpenGL on this device");
       
   638     }
       
   639     [static_cast<NSOpenGLContext *>(d->cx) update];
       
   640 #endif
       
   641 }
       
   642 
       
   643 void QGLContext::doneCurrent()
       
   644 {
       
   645 
       
   646     if (
       
   647 #ifndef QT_MAC_USE_COCOA
       
   648         aglGetCurrentContext() != (AGLContext) d_func()->cx
       
   649 #else
       
   650         [NSOpenGLContext currentContext] != d_func()->cx
       
   651 #endif
       
   652        )
       
   653         return;
       
   654 
       
   655     QGLContextPrivate::setCurrentContext(0);
       
   656 #ifndef QT_MAC_USE_COCOA
       
   657     aglSetCurrentContext(0);
       
   658 #else
       
   659     [NSOpenGLContext clearCurrentContext];
       
   660 #endif
       
   661 }
       
   662 
       
   663 void QGLContext::swapBuffers() const
       
   664 {
       
   665     Q_D(const QGLContext);
       
   666     if (!d->valid)
       
   667         return;
       
   668 #ifndef QT_MAC_USE_COCOA
       
   669     aglSwapBuffers((AGLContext)d->cx);
       
   670 #else
       
   671     [static_cast<NSOpenGLContext *>(d->cx) flushBuffer];
       
   672 #endif
       
   673 }
       
   674 
       
   675 QColor QGLContext::overlayTransparentColor() const
       
   676 {
       
   677     return QColor(0, 0, 0);                // Invalid color
       
   678 }
       
   679 
       
   680 #ifndef QT_MAC_USE_COCOA
       
   681 static QColor cmap[256];
       
   682 static bool cmap_init = false;
       
   683 #endif
       
   684 uint QGLContext::colorIndex(const QColor &c) const
       
   685 {
       
   686 #ifndef QT_MAC_USE_COCOA
       
   687     int ret = -1;
       
   688     if(!cmap_init) {
       
   689         cmap_init = true;
       
   690         for(int i = 0; i < 256; i++)
       
   691             cmap[i] = QColor();
       
   692     } else {
       
   693         for(int i = 0; i < 256; i++) {
       
   694             if(cmap[i].isValid() && cmap[i] == c) {
       
   695                 ret = i;
       
   696                 break;
       
   697             }
       
   698         }
       
   699     }
       
   700     if(ret == -1) {
       
   701         for(ret = 0; ret < 256; ret++)
       
   702             if(!cmap[ret].isValid())
       
   703                 break;
       
   704         if(ret == 256) {
       
   705             ret = -1;
       
   706             qWarning("QGLContext::colorIndex(): Internal error!");
       
   707         } else {
       
   708             cmap[ret] = c;
       
   709 
       
   710             GLint vals[4];
       
   711             vals[0] = ret;
       
   712             vals[1] = c.red();
       
   713             vals[2] = c.green();
       
   714             vals[3] = c.blue();
       
   715             aglSetInteger((AGLContext)d_func()->cx, AGL_COLORMAP_ENTRY, vals);
       
   716         }
       
   717     }
       
   718     return (uint)(ret == -1 ? 0 : ret);
       
   719 #else
       
   720     Q_UNUSED(c);
       
   721     return 0;
       
   722 #endif
       
   723 }
       
   724 
       
   725 void QGLContext::generateFontDisplayLists(const QFont & /* fnt */, int /* listBase */)
       
   726 {
       
   727 }
       
   728 
       
   729 static CFBundleRef qt_getOpenGLBundle()
       
   730 {
       
   731     CFBundleRef bundle = 0;
       
   732     QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
       
   733                  QCFString::toCFStringRef(QLatin1String("/System/Library/Frameworks/OpenGL.framework")), kCFURLPOSIXPathStyle, false);
       
   734     if (url)
       
   735         bundle = CFBundleCreate(kCFAllocatorDefault, url);
       
   736     return bundle;
       
   737 }
       
   738 
       
   739 void *QGLContext::getProcAddress(const QString &proc) const
       
   740 {
       
   741     return CFBundleGetFunctionPointerForName(QCFType<CFBundleRef>(qt_getOpenGLBundle()),
       
   742                                              QCFString(proc));
       
   743 }
       
   744 #ifndef QT_MAC_USE_COCOA
       
   745 /*****************************************************************************
       
   746   QGLWidget AGL-specific code
       
   747  *****************************************************************************/
       
   748 
       
   749 /****************************************************************************
       
   750   Hacks to glue AGL to an HIView
       
   751  ***************************************************************************/
       
   752 QRegion qt_mac_get_widget_rgn(const QWidget *widget)
       
   753 {
       
   754     if(!widget->isVisible() || widget->isMinimized())
       
   755         return QRegion();
       
   756     const QRect wrect = QRect(qt_mac_posInWindow(widget), widget->size());
       
   757     if(!wrect.isValid())
       
   758         return QRegion();
       
   759 
       
   760     RgnHandle macr = qt_mac_get_rgn();
       
   761     GetControlRegion((HIViewRef)widget->winId(), kControlStructureMetaPart, macr);
       
   762     OffsetRgn(macr, wrect.x(), wrect.y());
       
   763     QRegion ret = qt_mac_convert_mac_region(macr);
       
   764 
       
   765     QPoint clip_pos = wrect.topLeft();
       
   766     for(const QWidget *last_clip = 0, *clip = widget; clip; last_clip = clip, clip = clip->parentWidget()) {
       
   767         if(clip != widget) {
       
   768             GetControlRegion((HIViewRef)clip->winId(), kControlStructureMetaPart, macr);
       
   769             OffsetRgn(macr, clip_pos.x(), clip_pos.y());
       
   770             ret &= qt_mac_convert_mac_region(macr);
       
   771         }
       
   772         const QObjectList &children = clip->children();
       
   773         for(int i = children.size()-1; i >= 0; --i) {
       
   774             if(QWidget *child = qobject_cast<QWidget*>(children.at(i))) {
       
   775                 if(child == last_clip)
       
   776                     break;
       
   777 
       
   778                 // This check may seem weird, but when we are using a unified toolbar
       
   779                 // The widget is actually being owned by that toolbar and not by Qt.
       
   780                 // This means that the geometry it reports will be wrong
       
   781                 // and will accidentally cause problems when calculating the region
       
   782                 // So, it is better to skip these widgets since they aren't the hierarchy
       
   783                 // anyway.
       
   784                 if (HIViewGetSuperview(HIViewRef(child->winId())) != HIViewRef(clip->winId()))
       
   785                     continue;
       
   786 
       
   787                 if(child->isVisible() && !child->isMinimized() && !child->isTopLevel()) {
       
   788                     const QRect childRect = QRect(clip_pos+child->pos(), child->size());
       
   789                     if(childRect.isValid() && wrect.intersects(childRect)) {
       
   790                         GetControlRegion((HIViewRef)child->winId(), kControlStructureMetaPart, macr);
       
   791                         OffsetRgn(macr, childRect.x(), childRect.y());
       
   792                         ret -= qt_mac_convert_mac_region(macr);
       
   793                     }
       
   794                 }
       
   795             }
       
   796         }
       
   797         if(clip->isWindow())
       
   798             break;
       
   799         clip_pos -= clip->pos();
       
   800     }
       
   801     qt_mac_dispose_rgn(macr);
       
   802     return ret;
       
   803 }
       
   804 
       
   805 #endif
       
   806 
       
   807 void QGLWidget::setMouseTracking(bool enable)
       
   808 {
       
   809     QWidget::setMouseTracking(enable);
       
   810 }
       
   811 
       
   812 void QGLWidget::resizeEvent(QResizeEvent *)
       
   813 {
       
   814     Q_D(QGLWidget);
       
   815     if (!isValid())
       
   816         return;
       
   817 #ifndef QT_MAC_USE_COCOA
       
   818     if (!isWindow())
       
   819         d->glcx->d_func()->update = true;
       
   820 #endif
       
   821     makeCurrent();
       
   822     if (!d->glcx->initialized())
       
   823         glInit();
       
   824 #ifdef QT_MAC_USE_COCOA
       
   825     d->glcx->updatePaintDevice();
       
   826 #endif
       
   827 #ifndef QT_MAC_USE_COCOA
       
   828     float scale  = qt_mac_get_scale_factor(this);
       
   829     resizeGL(width() * scale, height() * scale);
       
   830 #else
       
   831     resizeGL(width(), height());
       
   832 #endif
       
   833 }
       
   834 
       
   835 const QGLContext* QGLWidget::overlayContext() const
       
   836 {
       
   837     return 0;
       
   838 }
       
   839 
       
   840 void QGLWidget::makeOverlayCurrent()
       
   841 {
       
   842 }
       
   843 
       
   844 void QGLWidget::updateOverlayGL()
       
   845 {
       
   846 }
       
   847 
       
   848 void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
       
   849 {
       
   850     Q_D(QGLWidget);
       
   851     if (context == 0) {
       
   852         qWarning("QGLWidget::setContext: Cannot set null context");
       
   853         return;
       
   854     }
       
   855 
       
   856     if (d->glcx)
       
   857         d->glcx->doneCurrent();
       
   858     QGLContext* oldcx = d->glcx;
       
   859     d->glcx = context;
       
   860     if (!d->glcx->isValid())
       
   861         d->glcx->create(shareContext ? shareContext : oldcx);
       
   862     if (deleteOldContext && oldcx)
       
   863         delete oldcx;
       
   864 }
       
   865 
       
   866 void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget *shareWidget)
       
   867 {
       
   868     Q_Q(QGLWidget);
       
   869 
       
   870     initContext(context, shareWidget);
       
   871 
       
   872     QWidget *current = q;
       
   873     while (current) {
       
   874         qt_widget_private(current)->glWidgets.append(QWidgetPrivate::GlWidgetInfo(q));
       
   875         if (current->isWindow())
       
   876             break;
       
   877         current = current->parentWidget();
       
   878     }
       
   879 
       
   880     isGLWidget = 1;
       
   881 }
       
   882 
       
   883 bool QGLWidgetPrivate::renderCxPm(QPixmap*)
       
   884 {
       
   885     return false;
       
   886 }
       
   887 
       
   888 void QGLWidgetPrivate::cleanupColormaps()
       
   889 {
       
   890 }
       
   891 
       
   892 const QGLColormap & QGLWidget::colormap() const
       
   893 {
       
   894     return d_func()->cmap;
       
   895 }
       
   896 
       
   897 void QGLWidget::setColormap(const QGLColormap &)
       
   898 {
       
   899 }
       
   900 
       
   901 void QGLWidgetPrivate::updatePaintDevice()
       
   902 {
       
   903     Q_Q(QGLWidget);
       
   904     glcx->updatePaintDevice();
       
   905     q->update();
       
   906 }
       
   907 
       
   908 
       
   909 void QGLExtensions::init()
       
   910 {
       
   911     static bool init_done = false;
       
   912 
       
   913     if (init_done)
       
   914         return;
       
   915     init_done = true;
       
   916 
       
   917 #ifndef QT_MAC_USE_COCOA
       
   918     GLint attribs[] = { AGL_RGBA, AGL_NONE };
       
   919     AGLPixelFormat fmt = aglChoosePixelFormat(0, 0, attribs);
       
   920     if (!fmt) {
       
   921         qDebug("QGLExtensions: Couldn't find any RGB visuals");
       
   922         return;
       
   923     }
       
   924     AGLContext ctx = aglCreateContext(fmt, 0);
       
   925     if (!ctx) {
       
   926         qDebug("QGLExtensions: Unable to create context");
       
   927     } else {
       
   928         aglSetCurrentContext(ctx);
       
   929         init_extensions();
       
   930         aglSetCurrentContext(0);
       
   931         aglDestroyContext(ctx);
       
   932     }
       
   933     aglDestroyPixelFormat(fmt);
       
   934 #else
       
   935     QMacCocoaAutoReleasePool pool;
       
   936     NSOpenGLPixelFormatAttribute attribs[] = { 0 };
       
   937     NSOpenGLPixelFormat *fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
       
   938     if (!fmt) {
       
   939         qWarning("QGLExtensions: Cannot find any visuals");
       
   940         return;
       
   941     }
       
   942 
       
   943     NSOpenGLContext *ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:0];
       
   944     if (!ctx) {
       
   945         qWarning("QGLExtensions: Cannot create context");
       
   946     } else {
       
   947         [ctx makeCurrentContext];
       
   948         init_extensions();
       
   949         [NSOpenGLContext clearCurrentContext];
       
   950         [ctx release];
       
   951     }
       
   952     [fmt release];
       
   953 #endif
       
   954 }
       
   955 
       
   956 #endif
       
   957 
       
   958 QT_END_NAMESPACE