source: trunk/src/opengl/qgl_mac.mm@ 754

Last change on this file since 754 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 31.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtOpenGL module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
82QT_BEGIN_NAMESPACE
83#ifdef QT_MAC_USE_COCOA
84QT_END_NAMESPACE
85
86QT_FORWARD_DECLARE_CLASS(QWidget)
87QT_FORWARD_DECLARE_CLASS(QWidgetPrivate)
88QT_FORWARD_DECLARE_CLASS(QGLWidgetPrivate)
89
90QT_BEGIN_NAMESPACE
91
92void *qt_current_nsopengl_context()
93{
94 return [NSOpenGLContext currentContext];
95}
96
97static GLint attribValue(NSOpenGLPixelFormat *fmt, NSOpenGLPixelFormatAttribute attrib)
98{
99 GLint res;
100 [fmt getValues:&res forAttribute:attrib forVirtualScreen:0];
101 return res;
102}
103
104static int def(int val, int defVal)
105{
106 return val != -1 ? val : defVal;
107}
108#else
109QRegion qt_mac_get_widget_rgn(const QWidget *widget);
110#endif
111
112extern quint32 *qt_mac_pixmap_get_base(const QPixmap *);
113extern int qt_mac_pixmap_get_bytes_per_line(const QPixmap *);
114extern RgnHandle qt_mac_get_rgn(); //qregion_mac.cpp
115extern void qt_mac_dispose_rgn(RgnHandle); //qregion_mac.cpp
116extern QRegion qt_mac_convert_mac_region(RgnHandle); //qregion_mac.cpp
117extern 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
123class QGLTemporaryContextPrivate
124{
125public:
126#ifndef QT_MAC_USE_COCOA
127 AGLContext ctx;
128#else
129 NSOpenGLContext *ctx;
130#endif
131};
132
133QGLTemporaryContext::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
168QGLTemporaryContext::~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
181bool QGLFormat::hasOpenGL()
182{
183 return true;
184}
185
186bool QGLFormat::hasOpenGLOverlays()
187{
188 return false;
189}
190
191bool 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
352void *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
477void 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
496void *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
514void 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
544void 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*/
569float 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*/
587void 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
718void 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
738void 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
750QColor QGLContext::overlayTransparentColor() const
751{
752 return QColor(0, 0, 0); // Invalid color
753}
754
755#ifndef QT_MAC_USE_COCOA
756static QColor cmap[256];
757static bool cmap_init = false;
758#endif
759uint 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
800void QGLContext::generateFontDisplayLists(const QFont & /* fnt */, int /* listBase */)
801{
802}
803
804static 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
814void *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 ***************************************************************************/
827QRegion 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
882void QGLWidget::setMouseTracking(bool enable)
883{
884 QWidget::setMouseTracking(enable);
885}
886
887void 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
910const QGLContext* QGLWidget::overlayContext() const
911{
912 return 0;
913}
914
915void QGLWidget::makeOverlayCurrent()
916{
917}
918
919void QGLWidget::updateOverlayGL()
920{
921}
922
923void 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
941void 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 isGLWidget = 1;
956}
957
958bool QGLWidgetPrivate::renderCxPm(QPixmap*)
959{
960 return false;
961}
962
963void QGLWidgetPrivate::cleanupColormaps()
964{
965}
966
967const QGLColormap & QGLWidget::colormap() const
968{
969 return d_func()->cmap;
970}
971
972void QGLWidget::setColormap(const QGLColormap &)
973{
974}
975
976void QGLWidgetPrivate::updatePaintDevice()