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