From f3aad61120d5cc8029c7092b1f74e2b5b632f99b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20R=C3=B8dal?= <samuel.rodal@digia.com>
Date: Tue, 14 May 2013 13:50:31 +0200
Subject: [PATCH] Fixed crash associated with reparenting a QGLWidget

We need to make sure that we don't reset() the context when the
QGLWidget is being reparented, as that will lead to the QOpenGLContext
being destroyed and not recreated, leading to a crash in makeCurrent().

Also, don't destroy() the widget if it has not yet been created, as in
that case there's no ParentAboutToChange event sent.

Task-number: QTBUG-31016

Change-Id: I409fff94456802a80bd72b470a6fbaee87505baa
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
Reviewed-by: Andy Nichols <andy.nichols@digia.com>
---
 src/opengl/qgl_p.h                 | 4 +++-
 src/opengl/qgl_qpa.cpp             | 9 +++++++++
 src/widgets/kernel/qwidget_qpa.cpp | 4 +---
 3 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index 9a58beb3d7d..ff9baf89716 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -132,6 +132,7 @@ class Q_OPENGL_EXPORT QGLWidgetPrivate : public QWidgetPrivate
 public:
     QGLWidgetPrivate() : QWidgetPrivate()
                        , disable_clear_on_painter_begin(false)
+                       , parent_changing(false)
     {
     }
 
@@ -142,7 +143,7 @@ public:
     bool renderCxPm(QPixmap *pixmap);
     void cleanupColormaps();
     void aboutToDestroy() {
-        if (glcx)
+        if (glcx && !parent_changing)
             glcx->reset();
     }
 
@@ -153,6 +154,7 @@ public:
     QGLColormap cmap;
 
     bool disable_clear_on_painter_begin;
+    bool parent_changing;
 };
 
 // QGLContextPrivate has the responsibility of creating context groups.
diff --git a/src/opengl/qgl_qpa.cpp b/src/opengl/qgl_qpa.cpp
index f3388ee5efc..6e698bf9399 100644
--- a/src/opengl/qgl_qpa.cpp
+++ b/src/opengl/qgl_qpa.cpp
@@ -362,6 +362,15 @@ void QGLWidgetPrivate::cleanupColormaps()
 
 bool QGLWidget::event(QEvent *e)
 {
+    Q_D(QGLWidget);
+
+    // A re-parent will destroy the window and re-create it. We should not reset the context while it happens.
+    if (e->type() == QEvent::ParentAboutToChange)
+        d->parent_changing = true;
+
+    if (e->type() == QEvent::ParentChange)
+        d->parent_changing = false;
+
     return QWidget::event(e);
 }
 
diff --git a/src/widgets/kernel/qwidget_qpa.cpp b/src/widgets/kernel/qwidget_qpa.cpp
index 590ebed5ebf..3b6c9ca4487 100644
--- a/src/widgets/kernel/qwidget_qpa.cpp
+++ b/src/widgets/kernel/qwidget_qpa.cpp
@@ -263,10 +263,8 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
     bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
 
     // Reparenting toplevel to child
-    if (!(f&Qt::Window) && (oldFlags&Qt::Window) && !q->testAttribute(Qt::WA_NativeWindow)) {
-        //qDebug() << "setParent_sys() change from toplevel";
+    if (wasCreated && !(f & Qt::Window) && (oldFlags & Qt::Window) && !q->testAttribute(Qt::WA_NativeWindow))
         q->destroy();
-    }
 
     adjustFlags(f, q);
     data.window_flags = f;
-- 
GitLab