From 08c4a88a77563e50860c34164414fe014271ccc2 Mon Sep 17 00:00:00 2001
From: Laszlo Agocs <laszlo.agocs@digia.com>
Date: Wed, 19 Feb 2014 13:31:51 +0100
Subject: [PATCH] Avoid extra platformwindows with QQuickWidget

QQuickWidget is nice but does not work on platforms like eglfs
because it always creates a (hidden) platform window for the
QQuickWindow.

This is now fixed by avoiding calling create() on the window and
using the toplevel window of the QQuickWidget instead.

Change-Id: Ia552f7a16d8b913fb798fde04b9304c6d037a46c
Reviewed-by: Paul Olav Tvete <paul.tvete@digia.com>
---
 src/quick/items/qquickrendercontrol.cpp | 10 +++++---
 src/quick/items/qquickwindow.cpp        |  3 +++
 src/quickwidgets/qquickwidget.cpp       | 32 ++++++++++++++++++-------
 3 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index 7e4335ba63..faee1358ae 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -114,9 +114,13 @@ void QQuickRenderControl::initialize(QOpenGLContext *gl)
     Q_D(QQuickRenderControl);
     if (!d->window)
         return;
-    bool current = gl->makeCurrent(d->window);
-    if (current)
-        QQuickWindowPrivate::get(d->window)->context->initialize(gl);
+
+    // It is the caller's responsiblity to make a context/surface current.
+    // It cannot be done here since the surface to use may not be the
+    // surface belonging to window. In fact window may not have a native
+    // window/surface at all.
+
+    QQuickWindowPrivate::get(d->window)->context->initialize(gl);
 }
 
 void QQuickRenderControl::invalidate()
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 7f62267859..588120a51a 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -361,6 +361,9 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
 {
     QML_MEMORY_SCOPE_STRING("SceneGraph");
     Q_Q(QQuickWindow);
+    if (!renderer)
+        return;
+
     animationController->advance();
     emit q->beforeRendering();
     int fboId = 0;
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index ec4ce2f314..e8dec60bc4 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -95,7 +95,7 @@ QQuickWidgetPrivate::QQuickWidgetPrivate()
     renderControl = new QQuickRenderControl;
     offscreenWindow = new QQuickWindow(renderControl);
     offscreenWindow->setTitle(QString::fromLatin1("Offscreen"));
-    offscreenWindow->create();
+    // Do not call create() on offscreenWindow.
 }
 
 QQuickWidgetPrivate::~QQuickWidgetPrivate()
@@ -155,7 +155,9 @@ void QQuickWidgetPrivate::renderSceneGraph()
         qWarning("QQuickWidget: render scenegraph with no context");
         return;
     }
-    context->makeCurrent(offscreenWindow);
+
+    Q_ASSERT(q->window()->windowHandle()->handle());
+    context->makeCurrent(q->window()->windowHandle());
     renderControl->polishItems();
     renderControl->sync();
     renderControl->render();
@@ -493,20 +495,25 @@ QSize QQuickWidgetPrivate::rootObjectSize() const
 
 void QQuickWidgetPrivate::createContext()
 {
+    Q_Q(QQuickWidget);
     if (context)
         return;
 
     context = new QOpenGLContext();
-    context->setFormat(offscreenWindow->requestedFormat());
+    context->setFormat(q->window()->windowHandle()->requestedFormat());
     if (QSGContext::sharedOpenGLContext())
         context->setShareContext(QSGContext::sharedOpenGLContext()); // ??? is this correct
     if (!context->create()) {
-        qWarning("QtQuick: failed to create OpenGL context");
+        qWarning("QQuickWidget: failed to create OpenGL context");
         delete context;
         context = 0;
     }
 
-    renderControl->initialize(context);
+    Q_ASSERT(q->window()->windowHandle()->handle());
+    if (context->makeCurrent(q->window()->windowHandle()))
+        renderControl->initialize(context);
+    else
+        qWarning("QQuickWidget: failed to make window surface current");
 }
 
 void QQuickWidget::createFramebufferObject()
@@ -518,7 +525,7 @@ void QQuickWidget::createFramebufferObject()
     QOpenGLContext *context = d->offscreenWindow->openglContext();
 
     if (!context) {
-        qWarning("createFBO with no context");
+        qWarning("QQuickWidget: Attempted to create FBO with no context");
         return;
     }
 
@@ -526,10 +533,17 @@ void QQuickWidget::createFramebufferObject()
         context->setShareContext(QWidgetPrivate::get(window())->shareContext());
         context->create();
     }
-    context->makeCurrent(d->offscreenWindow);
+
+    Q_ASSERT(window()->windowHandle()->handle());
+    context->makeCurrent(window()->windowHandle());
     d->fbo = new QOpenGLFramebufferObject(size());
     d->fbo->setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
     d->offscreenWindow->setRenderTarget(d->fbo);
+
+    // Sanity check: The window must not have an underlying platform window.
+    // Having one would mean create() was called and platforms that only support
+    // a single native window were in trouble.
+    Q_ASSERT(!d->offscreenWindow->handle());
 }
 
 void QQuickWidget::destroyFramebufferObject()
@@ -690,7 +704,9 @@ void QQuickWidget::resizeEvent(QResizeEvent *e)
         qWarning("QQuickWidget::resizeEvent() no OpenGL context");
         return;
     }
-    context->makeCurrent(d->offscreenWindow);
+
+    Q_ASSERT(window()->windowHandle()->handle());
+    context->makeCurrent(window()->windowHandle());
     d->renderControl->render();
     glFlush();
     context->doneCurrent();
-- 
GitLab