macOS: Propagate [NSOpenGLContext setView:] failures

Instead of trying to mask situations where [NSOpenGLContext setView:]
will fail (such as calling it for a view that's not part of a window
yet, or part of a window that hasn't been shown), we report the error
up through the API, so that QOpenGLContext::makeCurrent() will return
false. This is documented to occur e.g. when "the surface is not exposed,
or the graphics hardware is not available due to e.g. the application
being suspended."

QGLWidget was taught how to deal with this situation in cc27a50e. Other
Qt APIs seem to handle it fine, but if regressions occur they should be
fixable though the same logic as in cc27a50e.

Change-Id: I92775fc165444696b6c5b44fa0e28ce3c4ad2190
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@qt.io>
bb10
Tor Arne Vestbø 2018-07-30 14:22:24 +02:00
parent 68f20bb8f4
commit f8b17a297e
5 changed files with 25 additions and 55 deletions

View File

@ -75,7 +75,7 @@ public:
private:
static NSOpenGLPixelFormat *createNSOpenGLPixelFormat(const QSurfaceFormat &format);
void setActiveWindow(QWindow *window);
bool setActiveWindow(QWindow *window);
void updateSurfaceFormat();
NSOpenGLContext *m_context;

View File

@ -376,7 +376,10 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
return true;
QWindow *window = static_cast<QCocoaWindow *>(surface)->window();
setActiveWindow(window);
if (!setActiveWindow(window)) {
qCDebug(lcQpaOpenGLContext) << "Failed to activate window, skipping makeCurrent";
return false;
}
// Disable high-resolution surfaces when using the software renderer, which has the
// problem that the system silently falls back to a to using a low-resolution buffer
@ -397,23 +400,29 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
return true;
}
void QCocoaGLContext::setActiveWindow(QWindow *window)
bool QCocoaGLContext::setActiveWindow(QWindow *window)
{
if (window == m_currentWindow.data())
return;
return true;
Q_ASSERT(window->handle());
QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
NSView *view = cocoaWindow->view();
if ((m_context.view = view) != view) {
qCDebug(lcQpaOpenGLContext) << "Associating" << view << "with" << m_context << "failed";
return false;
}
qCDebug(lcQpaOpenGLContext) << m_context << "now associated with" << m_context.view;
if (m_currentWindow && m_currentWindow.data()->handle())
static_cast<QCocoaWindow *>(m_currentWindow.data()->handle())->setCurrentContext(0);
Q_ASSERT(window->handle());
m_currentWindow = window;
QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
cocoaWindow->setCurrentContext(this);
Q_ASSERT(!cocoaWindow->isForeignWindow());
[qnsview_cast(cocoaWindow->view()) setQCocoaGLContext:this];
return true;
}
// NSOpenGLContext is not re-entrant (https://openradar.appspot.com/37064579)
@ -431,7 +440,10 @@ void QCocoaGLContext::swapBuffers(QPlatformSurface *surface)
return; // Nothing to do
QWindow *window = static_cast<QCocoaWindow *>(surface)->window();
setActiveWindow(window);
if (!setActiveWindow(window)) {
qCWarning(lcQpaOpenGLContext) << "Failed to activate window, skipping swapBuffers";
return;
}
QMutexLocker locker(&s_contextMutex);
[m_context flushBuffer];

View File

@ -64,12 +64,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QCocoaNSMenuItem));
@end
@interface QT_MANGLE_NAMESPACE(QNSView) (DrawingAPI)
#ifndef QT_NO_OPENGL
- (void)setQCocoaGLContext:(QCocoaGLContext *)context;
#endif
@end
@interface QT_MANGLE_NAMESPACE(QNSView) (MouseAPI)
- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent;
- (void)resetMouseButtons;

View File

@ -122,10 +122,6 @@
bool m_dontOverrideCtrlLMB;
bool m_sendUpAsRightButton;
Qt::KeyboardModifiers m_currentWheelModifiers;
#ifndef QT_NO_OPENGL
QCocoaGLContext *m_glContext;
bool m_shouldSetGLContextinDrawRect;
#endif
NSString *m_inputSource;
QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) *m_mouseMoveHelper;
bool m_resendKeyEvent;
@ -143,10 +139,6 @@
m_acceptedMouseDowns = Qt::NoButton;
m_frameStrutButtons = Qt::NoButton;
m_sendKeyEvent = false;
#ifndef QT_NO_OPENGL
m_glContext = nullptr;
m_shouldSetGLContextinDrawRect = false;
#endif
m_sendUpAsRightButton = false;
m_inputSource = nil;
m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self];

View File

@ -39,22 +39,6 @@
// This file is included from qnsview.mm, and only used to organize the code
@implementation QT_MANGLE_NAMESPACE(QNSView) (DrawingAPI)
#ifndef QT_NO_OPENGL
- (void)setQCocoaGLContext:(QCocoaGLContext *)context
{
m_glContext = context;
[m_glContext->nsOpenGLContext() setView:self];
if (![m_glContext->nsOpenGLContext() view]) {
//was unable to set view
m_shouldSetGLContextinDrawRect = true;
}
}
#endif
@end
@implementation QT_MANGLE_NAMESPACE(QNSView) (Drawing)
- (BOOL)isOpaque
@ -84,19 +68,7 @@
exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect();
qCDebug(lcQpaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion;
[self updateRegion:exposedRegion];
}
- (void)updateRegion:(QRegion)dirtyRegion
{
#ifndef QT_NO_OPENGL
if (m_glContext && m_shouldSetGLContextinDrawRect) {
[m_glContext->nsOpenGLContext() setView:self];
m_shouldSetGLContextinDrawRect = false;
}
#endif
m_platformWindow->handleExposeEvent(dirtyRegion);
m_platformWindow->handleExposeEvent(exposedRegion);
}
- (BOOL)shouldUseMetalLayer
@ -174,7 +146,7 @@
qCDebug(lcQpaDrawing) << "[QNSView displayLayer]" << m_platformWindow->window();
// FIXME: Find out if there's a way to resolve the dirty rect like in drawRect:
[self updateRegion:QRectF::fromCGRect(self.bounds).toRect()];
m_platformWindow->handleExposeEvent(QRectF::fromCGRect(self.bounds).toRect());
}
- (void)viewDidChangeBackingProperties