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

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

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

File size: 30.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtOpenGL module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qgl.h"
43
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
119bool QGLFormat::hasOpenGL()
120{
121 return true;
122}
123
124bool QGLFormat::hasOpenGLOverlays()
125{
126 return false;
127}
128
129bool 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
290void *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
415void 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
434void *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
452void 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
481void 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 currentCtx = this;
497 if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
498 qgl_context_storage.setLocalData(new QGLThreadContext);
499 if (qgl_context_storage.hasLocalData())
500 qgl_context_storage.localData()->context = this;
501}
502
503#ifndef QT_MAC_USE_COCOA
504/*
505 Returns the effective scale factor for a widget. For this value to be
506 different than 1, the following must be true:
507 - The system scale factor must be greater than 1.
508 - The widget window must have WA_MacFrameworkScaled set.
509*/
510float qt_mac_get_scale_factor(QWidget *widget)
511{
512 if (!widget | !widget->window())
513 return 1;
514
515 if (widget->window()->testAttribute(Qt::WA_MacFrameworkScaled) == false)
516 return 1;
517
518 float systemScale = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4 ? HIGetScaleFactor() : 1;
519 if (systemScale == float(1))
520 return 1;
521
522 return systemScale;
523}
524#endif
525
526/*! \internal
527*/
528void QGLContext::updatePaintDevice()
529{
530 Q_D(QGLContext);
531#ifndef QT_MAC_USE_COCOA
532 d->update = false;
533 if (d->paintDevice->devType() == QInternal::Widget) {
534 //get control information
535 QWidget *w = (QWidget *)d->paintDevice;
536 HIViewRef hiview = (HIViewRef)w->winId();
537 WindowRef window = HIViewGetWindow(hiview);
538#ifdef DEBUG_OPENGL_REGION_UPDATE
539 static int serial_no_gl = 0;
540 qDebug("[%d] %p setting on %s::%s %p/%p [%s]", ++serial_no_gl, w,
541 w->metaObject()->className(), w->objectName().toLatin1().constData(),
542 hiview, window, w->handle() ? "Inside" : "Outside");
543#endif
544
545 //update drawable
546 if (0 && w->isWindow() && w->isFullScreen()) {
547 aglSetDrawable((AGLContext)d->cx, 0);
548 aglSetFullScreen((AGLContext)d->cx, w->width(), w->height(), 0, QApplication::desktop()->screenNumber(w));
549 w->hide();
550 } else {
551 AGLDrawable old_draw = aglGetDrawable((AGLContext)d->cx), new_draw = GetWindowPort(window);
552 if (old_draw != new_draw)
553 aglSetDrawable((AGLContext)d->cx, new_draw);
554 }
555
556 float scale = qt_mac_get_scale_factor(w);
557
558 if (!w->isWindow()) {
559 QRegion clp = qt_mac_get_widget_rgn(w); //get drawable area
560
561#ifdef DEBUG_OPENGL_REGION_UPDATE
562 if (clp.isEmpty()) {
563 qDebug(" Empty area!");
564 } else {
565 QVector<QRect> rs = clp.rects();
566 for(int i = 0; i < rs.count(); i++)
567 qDebug(" %d %d %d %d", rs[i].x(), rs[i].y(), rs[i].width(), rs[i].height());
568 }
569#endif
570 //update the clip
571 if (!aglIsEnabled((AGLContext)d->cx, AGL_BUFFER_RECT))
572 aglEnable((AGLContext)d->cx, AGL_BUFFER_RECT);
573 if (clp.isEmpty()) {
574 GLint offs[4] = { 0, 0, 0, 0 };
575 aglSetInteger((AGLContext)d->cx, AGL_BUFFER_RECT, offs);
576 if (aglIsEnabled((AGLContext)d->cx, AGL_CLIP_REGION))
577 aglDisable((AGLContext)d->cx, AGL_CLIP_REGION);
578 } else {
579 HIPoint origin = { 0., 0. };
580 HIViewConvertPoint(&origin, HIViewRef(w->winId()), 0);
581 const GLint offs[4] = { qRound(origin.x),
582 w->window()->frameGeometry().height() * scale
583 - (qRound(origin.y) + w->height() * scale),
584 w->width() * scale, w->height() * scale};
585
586 RgnHandle region = clp.handle(true);
587
588 if (scale != float(1)) {
589 // Sacle the clip region by the scale factor
590 Rect regionBounds;
591 GetRegionBounds(region, &regionBounds);
592 Rect regionBoundsDest = regionBounds;
593 regionBoundsDest.bottom *= scale;
594 regionBoundsDest.right *= scale;
595 MapRgn(region, &regionBounds, &regionBoundsDest);
596 }
597
598 aglSetInteger((AGLContext)d->cx, AGL_BUFFER_RECT, offs);
599 aglSetInteger((AGLContext)d->cx, AGL_CLIP_REGION, (const GLint *)region);
600 if (!aglIsEnabled((AGLContext)d->cx, AGL_CLIP_REGION))
601 aglEnable((AGLContext)d->cx, AGL_CLIP_REGION);
602 }
603 } else {
604 // Set the buffer rect for top-level gl contexts when scaled.
605 if (scale != float(1)) {
606 aglEnable((AGLContext)d->cx, AGL_BUFFER_RECT);
607 const GLint offs[4] = { 0, 0, w->width() * scale , w->height() * scale};
608 aglSetInteger((AGLContext)d->cx, AGL_BUFFER_RECT, offs);
609 }
610 }
611 } else if (d->paintDevice->devType() == QInternal::Pixmap) {
612 QPixmap *pm = (QPixmap *)d->paintDevice;
613 PixMapHandle mac_pm = GetGWorldPixMap((GWorldPtr)pm->macQDHandle());
614 aglSetOffScreen((AGLContext)d->cx, pm->width(), pm->height(),
615 GetPixRowBytes(mac_pm), GetPixBaseAddr(mac_pm));
616 } else {
617 qWarning("QGLContext::updatePaintDevice(): Not sure how to render OpenGL on this device!");
618 }
619 aglUpdateContext((AGLContext)d->cx);
620
621#else
622 QMacCocoaAutoReleasePool pool;
623
624 if (d->paintDevice->devType() == QInternal::Widget) {
625 //get control information
626 QWidget *w = (QWidget *)d->paintDevice;
627 NSView *view = qt_mac_nativeview_for(w);
628
629 // ideally we would use QWidget::isVisible(), but we get "invalid drawable" errors
630 if (![(NSWindow *)qt_mac_window_for(w) isVisible])
631 return;
632 if ([static_cast<NSOpenGLContext *>(d->cx) view] != view && ![view isHidden])
633 [static_cast<NSOpenGLContext *>(d->cx) setView:view];
634 } else if (d->paintDevice->devType() == QInternal::Pixmap) {
635 const QPixmap *pm = static_cast<const QPixmap *>(d->paintDevice);
636 [static_cast<NSOpenGLContext *>(d->cx) setOffScreen:qt_mac_pixmap_get_base(pm)
637 width:pm->width()
638 height:pm->height()
639 rowbytes:qt_mac_pixmap_get_bytes_per_line(pm)];
640 } else {
641 qWarning("QGLContext::updatePaintDevice: Not sure how to render OpenGL on this device");
642 }
643 [static_cast<NSOpenGLContext *>(d->cx) update];
644#endif
645}
646
647void QGLContext::doneCurrent()
648{
649
650 if (
651#ifndef QT_MAC_USE_COCOA
652 aglGetCurrentContext() != (AGLContext) d_func()->cx
653#else
654 [NSOpenGLContext currentContext] != d_func()->cx
655#endif
656 )
657 return;
658
659 currentCtx = 0;
660 if (qgl_context_storage.hasLocalData())
661 qgl_context_storage.localData()->context = 0;
662#ifndef QT_MAC_USE_COCOA
663 aglSetCurrentContext(0);
664#else
665 [NSOpenGLContext clearCurrentContext];
666#endif
667}
668
669void QGLContext::swapBuffers() const
670{
671 Q_D(const QGLContext);
672 if (!d->valid)
673 return;
674#ifndef QT_MAC_USE_COCOA
675 aglSwapBuffers((AGLContext)d->cx);
676#else
677 [static_cast<NSOpenGLContext *>(d->cx) flushBuffer];
678#endif
679}
680
681QColor QGLContext::overlayTransparentColor() const
682{
683 return QColor(0, 0, 0); // Invalid color
684}
685
686#ifndef QT_MAC_USE_COCOA
687static QColor cmap[256];
688static bool cmap_init = false;
689#endif
690uint QGLContext::colorIndex(const QColor &c) const
691{
692#ifndef QT_MAC_USE_COCOA
693 int ret = -1;
694 if(!cmap_init) {
695 cmap_init = true;
696 for(int i = 0; i < 256; i++)
697 cmap[i] = QColor();
698 } else {
699 for(int i = 0; i < 256; i++) {
700 if(cmap[i].isValid() && cmap[i] == c) {
701 ret = i;
702 break;
703 }
704 }
705 }
706 if(ret == -1) {
707 for(ret = 0; ret < 256; ret++)
708 if(!cmap[ret].isValid())
709 break;
710 if(ret == 256) {
711 ret = -1;
712 qWarning("QGLContext::colorIndex(): Internal error!");
713 } else {
714 cmap[ret] = c;
715
716 GLint vals[4];
717 vals[0] = ret;
718 vals[1] = c.red();
719 vals[2] = c.green();
720 vals[3] = c.blue();
721 aglSetInteger((AGLContext)d_func()->cx, AGL_COLORMAP_ENTRY, vals);
722 }
723 }
724 return (uint)(ret == -1 ? 0 : ret);
725#else
726 Q_UNUSED(c);
727 return 0;
728#endif
729}
730
731void QGLContext::generateFontDisplayLists(const QFont & /* fnt */, int /* listBase */)
732{
733}
734
735static CFBundleRef qt_getOpenGLBundle()
736{
737 CFBundleRef bundle = 0;
738 QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
739 QCFString::toCFStringRef(QLatin1String("/System/Library/Frameworks/OpenGL.framework")), kCFURLPOSIXPathStyle, false);
740 if (url)
741 bundle = CFBundleCreate(kCFAllocatorDefault, url);
742 return bundle;
743}
744
745void *QGLContext::getProcAddress(const QString &proc) const
746{
747 return CFBundleGetFunctionPointerForName(QCFType<CFBundleRef>(qt_getOpenGLBundle()),
748 QCFString(proc));
749}
750#ifndef QT_MAC_USE_COCOA
751/*****************************************************************************
752 QGLWidget AGL-specific code
753 *****************************************************************************/
754
755/****************************************************************************
756 Hacks to glue AGL to an HIView
757 ***************************************************************************/
758QRegion qt_mac_get_widget_rgn(const QWidget *widget)
759{
760 if(!widget->isVisible() || widget->isMinimized())
761 return QRegion();
762 const QRect wrect = QRect(qt_mac_posInWindow(widget), widget->size());
763 if(!wrect.isValid())
764 return QRegion();
765
766 RgnHandle macr = qt_mac_get_rgn();
767 GetControlRegion((HIViewRef)widget->winId(), kControlStructureMetaPart, macr);
768 OffsetRgn(macr, wrect.x(), wrect.y());
769 QRegion ret = qt_mac_convert_mac_region(macr);
770
771 QPoint clip_pos = wrect.topLeft();
772 for(const QWidget *last_clip = 0, *clip = widget; clip; last_clip = clip, clip = clip->parentWidget()) {
773 if(clip != widget) {
774 GetControlRegion((HIViewRef)clip->winId(), kControlStructureMetaPart, macr);
775 OffsetRgn(macr, clip_pos.x(), clip_pos.y());
776 ret &= qt_mac_convert_mac_region(macr);
777 }
778 const QObjectList &children = clip->children();
779 for(int i = children.size()-1; i >= 0; --i) {
780 if(QWidget *child = qobject_cast<QWidget*>(children.at(i))) {
781 if(child == last_clip)
782 break;
783
784 // This check may seem weird, but when we are using a unified toolbar
785 // The widget is actually being owned by that toolbar and not by Qt.
786 // This means that the geometry it reports will be wrong
787 // and will accidentally cause problems when calculating the region
788 // So, it is better to skip these widgets since they aren't the hierarchy
789 // anyway.
790 if (HIViewGetSuperview(HIViewRef(child->winId())) != HIViewRef(clip->winId()))
791 continue;
792
793 if(child->isVisible() && !child->isMinimized() && !child->isTopLevel()) {
794 const QRect childRect = QRect(clip_pos+child->pos(), child->size());
795 if(childRect.isValid() && wrect.intersects(childRect)) {
796 GetControlRegion((HIViewRef)child->winId(), kControlStructureMetaPart, macr);
797 OffsetRgn(macr, childRect.x(), childRect.y());
798 ret -= qt_mac_convert_mac_region(macr);
799 }
800 }
801 }
802 }
803 if(clip->isWindow())
804 break;
805 clip_pos -= clip->pos();
806 }
807 qt_mac_dispose_rgn(macr);
808 return ret;
809}
810
811#endif
812
813void QGLWidget::setMouseTracking(bool enable)
814{
815 QWidget::setMouseTracking(enable);
816}
817
818void QGLWidget::resizeEvent(QResizeEvent *)
819{
820 Q_D(QGLWidget);
821 if (!isValid())
822 return;
823#ifndef QT_MAC_USE_COCOA
824 if (!isWindow())
825 d->glcx->d_func()->update = true;
826#endif
827 makeCurrent();
828 if (!d->glcx->initialized())
829 glInit();
830#ifdef QT_MAC_USE_COCOA
831 d->glcx->updatePaintDevice();
832#endif
833#ifndef QT_MAC_USE_COCOA
834 float scale = qt_mac_get_scale_factor(this);
835 resizeGL(width() * scale, height() * scale);
836#else
837 resizeGL(width(), height());
838#endif
839}
840
841const QGLContext* QGLWidget::overlayContext() const
842{
843 return 0;
844}
845
846void QGLWidget::makeOverlayCurrent()
847{
848}
849
850void QGLWidget::updateOverlayGL()
851{
852}
853
854void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
855{
856 Q_D(QGLWidget);
857 if (context == 0) {
858 qWarning("QGLWidget::setContext: Cannot set null context");
859 return;
860 }
861
862 if (d->glcx)
863 d->glcx->doneCurrent();
864 QGLContext* oldcx = d->glcx;
865 d->glcx = context;
866 if (!d->glcx->isValid())
867 d->glcx->create(shareContext ? shareContext : oldcx);
868 if (deleteOldContext && oldcx)
869 delete oldcx;
870}
871
872void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget *shareWidget)
873{
874 Q_Q(QGLWidget);
875
876 initContext(context, shareWidget);
877
878 QWidget *current = q;
879 while (current) {
880 qt_widget_private(current)->glWidgets.append(QWidgetPrivate::GlWidgetInfo(q));
881 if (current->isWindow())
882 break;
883 current = current->parentWidget();
884 }
885
886 isGLWidget = 1;
887}
888
889bool QGLWidgetPrivate::renderCxPm(QPixmap*)
890{
891 return false;
892}
893
894void QGLWidgetPrivate::cleanupColormaps()
895{
896}
897
898const QGLColormap & QGLWidget::colormap() const
899{
900 return d_func()->cmap;
901}
902
903void QGLWidget::setColormap(const QGLColormap &)
904{
905}
906
907void QGLWidgetPrivate::updatePaintDevice()
908{
909 Q_Q(QGLWidget);
910 glcx->updatePaintDevice();
911 q->update();
912}
913
914
915void QGLExtensions::init()
916{
917 static bool init_done = false;
918
919 if (init_done)
920 return;
921 init_done = true;
922
923#ifndef QT_MAC_USE_COCOA
924 GLint attribs[] = { AGL_RGBA, AGL_NONE };
925 AGLPixelFormat fmt = aglChoosePixelFormat(0, 0, attribs);
926 if (!fmt) {
927 qDebug("QGLExtensions: Couldn't find any RGB visuals");
928 return;
929 }
930 AGLContext ctx = aglCreateContext(fmt, 0);
931 if (!ctx) {
932 qDebug("QGLExtensions: Unable to create context");
933 } else {
934 aglSetCurrentContext(ctx);
935 init_extensions();
936 aglSetCurrentContext(0);
937 aglDestroyContext(ctx);
938 }
939 aglDestroyPixelFormat(fmt);
940#else
941 QMacCocoaAutoReleasePool pool;
942 NSOpenGLPixelFormatAttribute attribs[] = { 0 };
943 NSOpenGLPixelFormat *fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
944 if (!fmt) {
945 qWarning("QGLExtensions: Cannot find any visuals");
946 return;
947 }
948
949 NSOpenGLContext *ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:0];
950 if (!ctx) {
951 qWarning("QGLExtensions: Cannot create context");
952 } else {
953 [ctx makeCurrentContext];
954 init_extensions();
955 [NSOpenGLContext clearCurrentContext];
956 [ctx release];
957 }
958 [fmt release];
959#endif
960}
961
962#endif
963
964QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.