summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@nokia.com>2010-09-02 13:18:31 (GMT)
committerTor Arne Vestbø <tor.arne.vestbo@nokia.com>2010-09-02 14:47:30 (GMT)
commit71a3b1a0d3ee6429832bdbf0da026cdc3f74080f (patch)
treed2254318ed1c4870238f2ae6b62edc19ba733319
parent03b7a3cffba609df56b4ccadacae6b6f985e96e9 (diff)
downloadQt-71a3b1a0d3ee6429832bdbf0da026cdc3f74080f.zip
Qt-71a3b1a0d3ee6429832bdbf0da026cdc3f74080f.tar.gz
Qt-71a3b1a0d3ee6429832bdbf0da026cdc3f74080f.tar.bz2
Ensure that OpenGL contexts are attached to an NSView before first paint
Attaching an OpenGL context to an NSView too soon will result in an error "invalid drawable" printed on the console. We used to guard against this by checking the visible property of the NSWindow, but this turned out to be too late, as we had already recived an initial paint event by then as part of showing the window. The visual result was a single frame of gray painted before the user's paint event code took effect. We solve this by hooking into setInitialFirstResponder on the NSWindow, which is called as part of making the window visible for the first time. At this point it's safe to attach the GL context to the NSView, so we iterate all the GLWidget children of the top level window and make sure the context is attached by sending a MacGLWindowChange event. The check in qt_mac_update_child_gl_widgets() for a top level window had to be removed for this approach to work, but should be okey as we're only iterating the children. Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@nokia.com> Reviewed-by: Trond Kjernåsen <trond.kjernasen@nokia.com>
-rw-r--r--src/gui/kernel/qapplication_mac.mm3
-rw-r--r--src/gui/kernel/qcocoasharedwindowmethods_mac_p.h13
-rw-r--r--src/opengl/qgl_mac.mm14
3 files changed, 24 insertions, 6 deletions
diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm
index 321492d..dd819e5 100644
--- a/src/gui/kernel/qapplication_mac.mm
+++ b/src/gui/kernel/qapplication_mac.mm
@@ -737,9 +737,6 @@ static void qt_post_window_change_event(QWidget *widget)
*/
static void qt_mac_update_child_gl_widgets(QWidget *widget)
{
- if (widget->isWindow())
- return;
-
// Update all OpenGL child widgets for the given widget.
QList<QWidgetPrivate::GlWidgetInfo> &glWidgets = qt_widget_private(widget)->glWidgets;
QList<QWidgetPrivate::GlWidgetInfo>::iterator end = glWidgets.end();
diff --git a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
index 6795149..16f5bd6 100644
--- a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
+++ b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
@@ -58,6 +58,8 @@ QT_BEGIN_NAMESPACE
extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); // qcocoaview.mm
extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
extern const QStringList& qEnabledDraggedTypes(); // qmime_mac.cpp
+extern void qt_event_request_window_change(QWidget *); // qapplication_mac.mm
+extern void qt_mac_send_posted_gl_updates(QWidget *widget); // qapplication_mac.mm
Q_GLOBAL_STATIC(QPointer<QWidget>, currentDragTarget);
@@ -227,6 +229,17 @@ QT_END_NAMESPACE
[self release];
}
+- (void)setInitialFirstResponder:(NSView *)view
+{
+ // This method is called the first time the window is placed on screen and
+ // is the earliest point in time we can connect OpenGL contexts to NSViews.
+ QWidget *qwidget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self];
+ qt_event_request_window_change(qwidget);
+ qt_mac_send_posted_gl_updates(qwidget);
+
+ [super setInitialFirstResponder:view];
+}
+
- (BOOL)makeFirstResponder:(NSResponder *)responder
{
// For some reason Cocoa wants to flip the first responder
diff --git a/src/opengl/qgl_mac.mm b/src/opengl/qgl_mac.mm
index 66fe7d3..f023a97 100644
--- a/src/opengl/qgl_mac.mm
+++ b/src/opengl/qgl_mac.mm
@@ -697,9 +697,17 @@ void QGLContext::updatePaintDevice()
QWidget *w = (QWidget *)d->paintDevice;
NSView *view = qt_mac_nativeview_for(w);
- // ideally we would use QWidget::isVisible(), but we get "invalid drawable" errors
- if (![(NSWindow *)qt_mac_window_for(w) isVisible])
- return;
+ // Trying to attach the GL context to the NSView will fail with
+ // "invalid drawable" if done too soon, but we have to make sure
+ // the connection is made before the first paint event. Using
+ // the NSView do to this check fails as the NSView is visible
+ // before it's safe to connect, and using the NSWindow fails as
+ // the NSWindow will become visible after the first paint event.
+ // This leaves us with the QWidget, who's visible state seems
+ // to match the point in time when it's safe to connect.
+ if (!w || !w->isVisible())
+ return; // Not safe to attach GL context to view yet
+
if ([static_cast<NSOpenGLContext *>(d->cx) view] != view && ![view isHidden])
[static_cast<NSOpenGLContext *>(d->cx) setView:view];
} else if (d->paintDevice->devType() == QInternal::Pixmap) {