diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index 308706f0b91a0ec65a4f7f261f6b7b3f6f704994..a224db31d6a3ae877d2d8e2625c89c6018af8cf0 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -67,7 +67,8 @@ HEADERS += \
     $$PWD/qquickmultipointtoucharea_p.h \
     $$PWD/qquickitemview_p.h \
     $$PWD/qquickitemview_p_p.h \
-    $$PWD/qquickwindowmodule_p.h
+    $$PWD/qquickwindowmodule_p.h \
+    $$PWD/qquickwindowmanager_p.h
 
 SOURCES += \
     $$PWD/qquickevents.cpp \
@@ -114,7 +115,8 @@ SOURCES += \
     $$PWD/qquickdroparea.cpp \
     $$PWD/qquickmultipointtoucharea.cpp \
     $$PWD/qquickitemview.cpp \
-    $$PWD/qquickwindowmodule.cpp
+    $$PWD/qquickwindowmodule.cpp \
+    $$PWD/qquickwindowmanager.cpp
 
 SOURCES += \
     $$PWD/qquickshadereffect.cpp \
@@ -129,3 +131,5 @@ HEADERS += \
     $$PWD/qquickshadereffectsource_p.h \
 
 include(context2d/context2d.pri)
+
+
diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp
index 9c6ab08fc7b0840d04b52c514943e437d9aafb40..5bf27dea5b74ea3a28a1a139b73fff3be4fb37fd 100644
--- a/src/quick/items/qquickcanvas.cpp
+++ b/src/quick/items/qquickcanvas.cpp
@@ -45,10 +45,12 @@
 #include "qquickitem.h"
 #include "qquickitem_p.h"
 
-#include <QtQuick/private/qsgrenderer_p.h>
-#include <QtQuick/private/qsgtexture_p.h>
+#include <private/qsgrenderer_p.h>
+#include <private/qsgtexture_p.h>
 #include <private/qsgflashnode_p.h>
-#include <QtQuick/qsgengine.h>
+#include <qsgengine.h>
+
+#include <private/qquickwindowmanager_p.h>
 
 #include <private/qguiapplication_p.h>
 #include <QtGui/QInputPanel>
@@ -66,19 +68,6 @@
 
 QT_BEGIN_NAMESPACE
 
-#define QQUICK_CANVAS_TIMING
-#ifdef QQUICK_CANVAS_TIMING
-static bool qquick_canvas_timing = !qgetenv("QML_CANVAS_TIMING").isEmpty();
-static QTime threadTimer;
-static int syncTime;
-static int renderTime;
-static int swapTime;
-#endif
-
-DEFINE_BOOL_CONFIG_OPTION(qmlFixedAnimationStep, QML_FIXED_ANIMATION_STEP)
-DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_BAD_GUI_RENDER_LOOP)
-
-extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
 
 void QQuickCanvasPrivate::updateFocusItemTransform()
 {
@@ -100,7 +89,7 @@ protected:
         if (e->type() == QEvent::User) {
             Q_ASSERT(m_eventSent);
 
-            bool *amtp = m_canvas->thread->allowMainThreadProcessing();
+            bool *amtp = m_canvas->windowManager->allowMainThreadProcessing();
             while (incubatingObjectCount()) {
                 if (amtp)
                     incubateWhile(amtp);
@@ -127,83 +116,6 @@ private:
     bool m_eventSent;
 };
 
-class QQuickCanvasPlainRenderLoop : public QObject, public QQuickCanvasRenderLoop
-{
-public:
-    QQuickCanvasPlainRenderLoop()
-        : updatePending(false)
-        , animationRunning(false)
-    {
-    }
-
-    virtual void paint() {
-        updatePending = false;
-        if (animationRunning && animationDriver())
-            animationDriver()->advance();
-        polishItems();
-        syncSceneGraph();
-        makeCurrent();
-        glViewport(0, 0, size.width(), size.height());
-        renderSceneGraph(size);
-        swapBuffers();
-
-        if (animationRunning)
-            maybeUpdate();
-    }
-
-    virtual QImage grab() {
-        return qt_gl_read_framebuffer(size, false, false);
-    }
-
-    virtual void startRendering() {
-        if (!glContext()) {
-            createGLContext();
-            makeCurrent();
-            initializeSceneGraph();
-        } else {
-            makeCurrent();
-        }
-        maybeUpdate();
-    }
-
-    virtual void stopRendering() {
-        cleanupNodesOnShutdown();
-    }
-
-    virtual void maybeUpdate() {
-        if (!updatePending) {
-            QCoreApplication::postEvent(this, new QEvent(QEvent::User));
-            updatePending = true;
-        }
-    }
-
-    virtual void animationStarted() {
-        animationRunning = true;
-        maybeUpdate();
-    }
-
-    virtual void animationStopped() {
-        animationRunning = false;
-    }
-
-    virtual bool isRunning() const { return glContext(); } // Event loop is always running...
-    virtual void resize(const QSize &s) { size = s; }
-    virtual void setWindowSize(const QSize &s) { size = s; }
-
-    bool event(QEvent *e) {
-        if (e->type() == QEvent::User) {
-            paint();
-            return true;
-        }
-        return QObject::event(e);
-    }
-
-    QSize size;
-
-    uint updatePending : 1;
-    uint animationRunning : 1;
-};
-
 
 
 /*
@@ -225,74 +137,11 @@ thus the first item that has focus will get it (assuming the scope doesn't alrea
 have a scope focused item), and the other items will have their focus cleared.
 */
 
-/*
-  Threaded Rendering
-  ==================
-
-  The threaded rendering uses a number of different variables to track potential
-  states used to handle resizing, initial paint, grabbing and driving animations
-  while ALWAYS keeping the GL context in the rendering thread and keeping the
-  overhead of normal one-shot paints and vblank driven animations at a minimum.
-
-  Resize, initial show and grab suffer slightly in this model as they are locked
-  to the rendering in the rendering thread, but this is a necessary evil for
-  the system to work.
-
-  Variables that are used:
-
-  Private::animationRunning: This is true while the animations are running, and only
-  written to inside locks.
-
-  RenderThread::isGuiBlocked: This is used to indicate that the GUI thread owns the
-  lock. This variable is an integer to allow for recursive calls to lockInGui()
-  without using a recursive mutex. See isGuiBlockPending.
-
-  RenderThread::isPaintComplete: This variable is cleared when rendering starts and
-  set once rendering is complete. It is monitored in the paintEvent(),
-  resizeEvent() and grab() functions to force them to wait for rendering to
-  complete.
-
-  RenderThread::isGuiBlockPending: This variable is set in the render thread just
-  before the sync event is sent to the GUI thread. It is used to avoid deadlocks
-  in the case where render thread waits while waiting for GUI to pick up the sync
-  event and GUI thread gets a resizeEvent, the initial paintEvent or a grab.
-  When this happens, we use the
-  exhaustSyncEvent() function to do the sync right there and mark the coming
-  sync event to be discarded. There can only ever be one sync incoming.
-
-  RenderThread::isRenderBlock: This variable is true when animations are not
-  running and the render thread has gone to sleep, waiting for more to do.
-
-  RenderThread::isExternalUpdatePending: This variable is set to false when
-  a new render pass is started and to true in maybeUpdate(). It is an
-  indication to the render thread that another render pass needs to take
-  place, rather than the render thread going to sleep after completing its swap.
-
-  RenderThread::doGrab: This variable is set by the grab() function and
-  tells the renderer to do a grab after rendering is complete and before
-  swapping happens.
-
-  RenderThread::shouldExit: This variable is used to determine if the render
-  thread should do a nother pass. It is typically set as a result of show()
-  and unset as a result of hide() or during shutdown()
-
-  RenderThread::hasExited: Used by the GUI thread to synchronize the shutdown
-  after shouldExit has been set to true.
- */
 
 // #define FOCUS_DEBUG
 // #define MOUSE_DEBUG
 // #define TOUCH_DEBUG
 // #define DIRTY_DEBUG
-// #define THREAD_DEBUG
-
-// #define FRAME_TIMING
-
-#ifdef FRAME_TIMING
-static QTime frameTimer;
-int sceneGraphRenderTime;
-int readbackTime;
-#endif
 
 QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
 : transformNode(0)
@@ -306,47 +155,23 @@ QQuickRootItem::QQuickRootItem()
 void QQuickCanvas::exposeEvent(QExposeEvent *)
 {
     Q_D(QQuickCanvas);
-    d->thread->paint();
+    d->windowManager->paint(this);
 }
 
 void QQuickCanvas::resizeEvent(QResizeEvent *)
 {
     Q_D(QQuickCanvas);
-    d->thread->resize(size());
-}
-
-void QQuickCanvas::animationStarted()
-{
-    d_func()->thread->animationStarted();
-}
-
-void QQuickCanvas::animationStopped()
-{
-    d_func()->thread->animationStopped();
+    d->windowManager->resize(this, size());
 }
 
 void QQuickCanvas::showEvent(QShowEvent *)
 {
-    Q_D(QQuickCanvas);
-    if (d->vsyncAnimations) {
-        if (!d->animationDriver) {
-            d->animationDriver = d->context->createAnimationDriver(this);
-            connect(d->animationDriver, SIGNAL(started()), this, SLOT(animationStarted()), Qt::DirectConnection);
-            connect(d->animationDriver, SIGNAL(stopped()), this, SLOT(animationStopped()), Qt::DirectConnection);
-        }
-        d->animationDriver->install();
-    }
-
-    if (!d->thread->isRunning()) {
-        d->thread->setWindowSize(size());
-        d->thread->startRendering();
-    }
+    d_func()->windowManager->show(this);
 }
 
 void QQuickCanvas::hideEvent(QHideEvent *)
 {
-    Q_D(QQuickCanvas);
-    d->thread->stopRendering();
+    d_func()->windowManager->hide(this);
 }
 
 void QQuickCanvas::focusOutEvent(QFocusEvent *)
@@ -362,64 +187,6 @@ void QQuickCanvas::focusInEvent(QFocusEvent *)
 }
 
 
-/*!
-    Sets weither this canvas should use vsync driven animations.
-
-    This option can only be set on one single QQuickCanvas, and that it's
-    vsync signal will then be used to drive all animations in the
-    process.
-
-    This feature is primarily useful for single QQuickCanvas, QML-only
-    applications.
-
-    \warning Enabling vsync on multiple QQuickCanvas instances has
-    undefined behavior.
- */
-void QQuickCanvas::setVSyncAnimations(bool enabled)
-{
-    Q_D(QQuickCanvas);
-    if (visible()) {
-        qWarning("QQuickCanvas::setVSyncAnimations: Cannot be changed when widget is shown");
-        return;
-    }
-    d->vsyncAnimations = enabled;
-}
-
-
-
-/*!
-    Returns true if this canvas should use vsync driven animations;
-    otherwise returns false.
- */
-bool QQuickCanvas::vsyncAnimations() const
-{
-    Q_D(const QQuickCanvas);
-    return d->vsyncAnimations;
-}
-
-void QQuickCanvasPrivate::initializeSceneGraph()
-{
-    if (!context)
-        context = QSGContext::createDefaultContext();
-
-    if (context->isReady())
-        return;
-
-    QOpenGLContext *glctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
-    context->initialize(glctx);
-
-    Q_Q(QQuickCanvas);
-
-    if (!QQuickItemPrivate::get(rootItem)->itemNode()->parent()) {
-        context->rootNode()->appendChildNode(QQuickItemPrivate::get(rootItem)->itemNode());
-    }
-
-    engine = new QSGEngine();
-    engine->setCanvas(q);
-
-    emit q_func()->sceneGraphInitialized();
-}
-
 void QQuickCanvasPrivate::polishItems()
 {
     while (!itemsToPolish.isEmpty()) {
@@ -435,51 +202,46 @@ void QQuickCanvasPrivate::polishItems()
 
 void QQuickCanvasPrivate::syncSceneGraph()
 {
+    if (!renderer) {
+        QSGRootNode *rootNode = new QSGRootNode;
+        rootNode->appendChildNode(QQuickItemPrivate::get(rootItem)->itemNode());
+        renderer = context->createRenderer();
+        renderer->setRootNode(rootNode);
+    }
+
     updateDirtyNodes();
 
     // Copy the current state of clearing from canvas into renderer.
-    context->renderer()->setClearColor(clearColor);
+    renderer->setClearColor(clearColor);
     QSGRenderer::ClearMode mode = QSGRenderer::ClearStencilBuffer | QSGRenderer::ClearDepthBuffer;
     if (clearBeforeRendering)
         mode |= QSGRenderer::ClearColorBuffer;
-    context->renderer()->setClearMode(mode);
+    renderer->setClearMode(mode);
 }
 
 
 void QQuickCanvasPrivate::renderSceneGraph(const QSize &size)
 {
     Q_Q(QQuickCanvas);
-    context->renderer()->setDeviceRect(QRect(QPoint(0, 0), size));
-    context->renderer()->setViewportRect(QRect(QPoint(0, 0), renderTarget ? renderTarget->size() : size));
-    context->renderer()->setProjectionMatrixToDeviceRect();
+    renderer->setDeviceRect(QRect(QPoint(0, 0), size));
+    renderer->setViewportRect(QRect(QPoint(0, 0), renderTarget ? renderTarget->size() : size));
+    renderer->setProjectionMatrixToDeviceRect();
 
     emit q->beforeRendering();
-    context->renderNextFrame(renderTarget);
+    context->renderNextFrame(renderer, renderTarget);
     emit q->afterRendering();
-
-#ifdef FRAME_TIMING
-    sceneGraphRenderTime = frameTimer.elapsed();
-#endif
-
-#ifdef FRAME_TIMING
-//    int pixel;
-//    glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
-    readbackTime = frameTimer.elapsed();
-#endif
 }
 
-
 QQuickCanvasPrivate::QQuickCanvasPrivate()
     : rootItem(0)
     , activeFocusItem(0)
     , mouseGrabberItem(0)
     , dirtyItemList(0)
     , context(0)
+    , renderer(0)
+    , windowManager(0)
     , clearColor(Qt::white)
-    , vsyncAnimations(false)
     , clearBeforeRendering(true)
-    , thread(0)
-    , animationDriver(0)
     , renderTarget(0)
     , incubationController(0)
 {
@@ -491,10 +253,6 @@ QQuickCanvasPrivate::~QQuickCanvasPrivate()
 
 void QQuickCanvasPrivate::init(QQuickCanvas *c)
 {
-    QUnifiedTimer* ut = QUnifiedTimer::instance(true);
-    if (qmlFixedAnimationStep())
-        ut->setConsistentTiming(true);
-
     q_ptr = c;
 
     Q_Q(QQuickCanvas);
@@ -510,26 +268,18 @@ void QQuickCanvasPrivate::init(QQuickCanvas *c)
     //It is important that this call happens after the rootItem has a canvas..
     rootItem->setFocus(true);
 
-    bool threaded = !qmlNoThreadedRenderer();
-
-    if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL)) {
-        qWarning("QQuickCanvas: platform does not support threaded rendering!");
-        threaded = false;
-    }
-
-    if (threaded)
-        thread = new QQuickCanvasRenderThread();
-    else
-        thread = new QQuickCanvasPlainRenderLoop();
-
-    thread->renderer = q;
-    thread->d = this;
-
-    context = QSGContext::createDefaultContext();
-    thread->moveContextToThread(context);
-
+    windowManager = QQuickWindowManager::instance();
+    context = windowManager->sceneGraphContext();
     q->setSurfaceType(QWindow::OpenGLSurface);
     q->setFormat(context->defaultSurfaceFormat());
+
+    QObject::connect(context, SIGNAL(initialized()), q, SIGNAL(sceneGraphInitialized()));
+    QObject::connect(context, SIGNAL(invalidated()), q, SIGNAL(sceneGraphInvalidated()));
+    QObject::connect(context, SIGNAL(invalidated()), q, SLOT(cleanupSceneGraph()));
+
+    // ### TODO: remove QSGEngine
+    engine = new QSGEngine();
+    engine->setCanvas(q);
 }
 
 QDeclarativeListProperty<QObject> QQuickCanvasPrivate::data()
@@ -844,8 +594,6 @@ void QQuickCanvasPrivate::cleanup(QSGNode *n)
     \since QtQuick 2.0
     \brief The QQuickCanvas class provides the canvas for displaying a graphical QML scene
 
-    \inmodule QtQuick
-
     QQuickCanvas provides the graphical scene management needed to interact with and display
     a scene of QQuickItems.
 
@@ -872,8 +620,7 @@ QQuickCanvas::~QQuickCanvas()
 {
     Q_D(QQuickCanvas);
 
-    if (d->thread->isRunning())
-        d->thread->stopRendering();
+    d->windowManager->canvasDestroyed(this);
 
     // ### should we change ~QQuickItem to handle this better?
     // manually cleanup for the root item (item destructor only handles these when an item is parented)
@@ -883,8 +630,6 @@ QQuickCanvas::~QQuickCanvas()
     delete d->incubationController; d->incubationController = 0;
 
     delete d->rootItem; d->rootItem = 0;
-
-    delete d->thread; d->thread = 0;
 }
 
 /*!
@@ -1918,9 +1663,20 @@ void QQuickCanvasPrivate::updateDirtyNode(QQuickItem *item)
 void QQuickCanvas::maybeUpdate()
 {
     Q_D(QQuickCanvas);
+    d->windowManager->maybeUpdate(this);
+}
+
+void QQuickCanvas::cleanupSceneGraph()
+{
+    Q_D(QQuickCanvas);
+
+    if (!d->renderer)
+        return;
+
+    delete d->renderer->rootNode();
+    delete d->renderer;
 
-    if (d->thread && d->thread->isRunning())
-        d->thread->maybeUpdate();
+    d->renderer = 0;
 }
 
 /*!
@@ -2001,7 +1757,7 @@ QOpenGLFramebufferObject *QQuickCanvas::renderTarget() const
 QImage QQuickCanvas::grabFrameBuffer()
 {
     Q_D(QQuickCanvas);
-    return d->thread ? d->thread->grab() : QImage();
+    return d->windowManager->grab(this);
 }
 
 /*!
@@ -2120,7 +1876,7 @@ bool QQuickCanvas::clearBeforeRendering() const
 QSGTexture *QQuickCanvas::createTextureFromImage(const QImage &image) const
 {
     Q_D(const QQuickCanvas);
-    if (d->context)
+    if (d->context && d->context->isReady())
         return d->context->createTexture(image);
     else
         return 0;
@@ -2143,7 +1899,7 @@ QSGTexture *QQuickCanvas::createTextureFromImage(const QImage &image) const
 QSGTexture *QQuickCanvas::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
 {
     Q_D(const QQuickCanvas);
-    if (d->context) {
+    if (d->context && d->context->isReady()) {
         QSGPlainTexture *texture = new QSGPlainTexture();
         texture->setTextureId(id);
         texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
@@ -2166,9 +1922,11 @@ QSGTexture *QQuickCanvas::createTextureFromId(uint id, const QSize &size, Create
 
 void QQuickCanvas::setClearColor(const QColor &color)
 {
-    if (color == d_func()->clearColor)
+    Q_D(QQuickCanvas);
+    if (color == d->clearColor)
         return;
-    d_func()->clearColor = color;
+
+    d->clearColor = color;
     emit clearColorChanged(color);
 }
 
@@ -2185,462 +1943,6 @@ QColor QQuickCanvas::clearColor() const
 
 
 
-void QQuickCanvasRenderLoop::createGLContext()
-{
-    gl = new QOpenGLContext();
-    gl->setFormat(renderer->requestedFormat());
-    gl->create();
-}
-
-void QQuickCanvasRenderThread::run()
-{
-#ifdef THREAD_DEBUG
-    qDebug("QML Rendering Thread Started");
-#endif
-
-    if (!glContext()) {
-        createGLContext();
-        makeCurrent();
-        initializeSceneGraph();
-    } else {
-        makeCurrent();
-    }
-
-    while (!shouldExit) {
-        lock();
-
-        bool sizeChanged = false;
-        isExternalUpdatePending = false;
-
-        if (renderedSize != windowSize) {
-#ifdef THREAD_DEBUG
-            printf("                RenderThread: window has changed size...\n");
-#endif
-            glViewport(0, 0, windowSize.width(), windowSize.height());
-            sizeChanged = true;
-        }
-
-#ifdef THREAD_DEBUG
-        printf("                RenderThread: preparing to sync...\n");
-#endif
-
-        if (!isGuiBlocked) {
-            isGuiBlockPending = true;
-
-#ifdef THREAD_DEBUG
-            printf("                RenderThread: aquired sync lock...\n");
-#endif
-            allowMainThreadProcessingFlag = false;
-            QCoreApplication::postEvent(this, new QEvent(QEvent::User));
-#ifdef THREAD_DEBUG
-            printf("                RenderThread: going to sleep...\n");
-#endif
-            wait();
-
-            isGuiBlockPending = false;
-        }
-
-#ifdef THREAD_DEBUG
-        printf("                RenderThread: Doing locked sync\n");
-#endif
-#ifdef QQUICK_CANVAS_TIMING
-        if (qquick_canvas_timing)
-            threadTimer.start();
-#endif
-        inSync = true;
-        syncSceneGraph();
-        inSync = false;
-
-        // Wake GUI after sync to let it continue animating and event processing.
-        allowMainThreadProcessingFlag = true;
-        wake();
-        unlock();
-#ifdef THREAD_DEBUG
-        printf("                RenderThread: sync done\n");
-#endif
-#ifdef QQUICK_CANVAS_TIMING
-        if (qquick_canvas_timing)
-            syncTime = threadTimer.elapsed();
-#endif
-
-#ifdef THREAD_DEBUG
-        printf("                RenderThread: rendering... %d x %d\n", windowSize.width(), windowSize.height());
-#endif
-
-        renderSceneGraph(windowSize);
-#ifdef QQUICK_CANVAS_TIMING
-        if (qquick_canvas_timing)
-            renderTime = threadTimer.elapsed() - syncTime;
-#endif
-
-        // The content of the target buffer is undefined after swap() so grab needs
-        // to happen before swap();
-        if (doGrab) {
-#ifdef THREAD_DEBUG
-            printf("                RenderThread: doing a grab...\n");
-#endif
-            grabContent = qt_gl_read_framebuffer(windowSize, false, false);
-            doGrab = false;
-        }
-
-#ifdef THREAD_DEBUG
-        printf("                RenderThread: wait for swap...\n");
-#endif
-
-        swapBuffers();
-#ifdef THREAD_DEBUG
-        printf("                RenderThread: swap complete...\n");
-#endif
-#ifdef QQUICK_CANVAS_TIMING
-        if (qquick_canvas_timing) {
-            swapTime = threadTimer.elapsed() - renderTime;
-            qDebug() << "- Breakdown of frame time: sync:" << syncTime
-                     << "ms render:" << renderTime << "ms swap:" << swapTime
-                     << "ms total:" << swapTime + renderTime << "ms";
-        }
-#endif
-
-        lock();
-        isPaintCompleted = true;
-        if (sizeChanged)
-            renderedSize = windowSize;
-
-        // Wake the GUI thread now that rendering is complete, to signal that painting
-        // is done, resizing is done or grabbing is completed. For grabbing, we're
-        // signalling this much later than needed (we could have done it before swap)
-        // but we don't want to lock an extra time.
-        wake();
-
-        if (!animationRunning && !isExternalUpdatePending && !shouldExit && !doGrab) {
-#ifdef THREAD_DEBUG
-            printf("                RenderThread: nothing to do, going to sleep...\n");
-#endif
-            isRenderBlocked = true;
-            wait();
-            isRenderBlocked = false;
-        }
-
-        unlock();
-
-        QCoreApplication::processEvents();
-
-        // Process any "deleteLater" objects...
-        QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
-    }
-
-#ifdef THREAD_DEBUG
-    printf("                RenderThread: deleting all outstanding nodes\n");
-#endif
-    cleanupNodesOnShutdown();
-
-#ifdef THREAD_DEBUG
-    printf("                RenderThread: render loop exited... Good Night!\n");
-#endif
-
-    doneCurrent();
-
-    lock();
-    hasExited = true;
-#ifdef THREAD_DEBUG
-    printf("                RenderThread: waking GUI for final sleep..\n");
-#endif
-    wake();
-    unlock();
-
-#ifdef THREAD_DEBUG
-    printf("                RenderThread: All done...\n");
-#endif
-}
-
-
-
-bool QQuickCanvasRenderThread::event(QEvent *e)
-{
-    Q_ASSERT(QThread::currentThread() == qApp->thread());
-
-    if (e->type() == QEvent::User) {
-        if (!syncAlreadyHappened)
-            sync(false);
-
-        syncAlreadyHappened = false;
-
-        if (animationRunning && animationDriver()) {
-#ifdef THREAD_DEBUG
-            qDebug("GUI: Advancing animations...\n");
-#endif
-
-            animationDriver()->advance();
-
-#ifdef THREAD_DEBUG
-            qDebug("GUI: Animations advanced...\n");
-#endif
-        }
-
-        return true;
-    }
-
-    return QThread::event(e);
-}
-
-
-
-void QQuickCanvasRenderThread::exhaustSyncEvent()
-{
-    if (isGuiBlockPending) {
-        sync(true);
-        syncAlreadyHappened = true;
-    }
-}
-
-
-
-void QQuickCanvasRenderThread::sync(bool guiAlreadyLocked)
-{
-#ifdef THREAD_DEBUG
-    printf("GUI: sync - %s\n", guiAlreadyLocked ? "outside event" : "inside event");
-#endif
-    if (!guiAlreadyLocked)
-        lockInGui();
-
-    renderThreadAwakened = false;
-
-    polishItems();
-
-    wake();
-    wait();
-
-    if (!guiAlreadyLocked)
-        unlockInGui();
-}
-
-
-
-
-/*!
-    Acquires the mutex for the GUI thread. The function uses the isGuiBlocked
-    variable to keep track of how many recursion levels the gui is locked with.
-    We only actually acquire the mutex for the first level to avoid deadlocking
-    ourselves.
- */
-
-void QQuickCanvasRenderThread::lockInGui()
-{
-    // We must avoid recursive locking in the GUI thread, hence we
-    // only lock when we are the first one to try to block.
-    if (!isGuiBlocked)
-        lock();
-
-    isGuiBlocked++;
-
-#ifdef THREAD_DEBUG
-    printf("GUI: aquired lock... %d\n", isGuiBlocked);
-#endif
-}
-
-
-
-void QQuickCanvasRenderThread::unlockInGui()
-{
-#ifdef THREAD_DEBUG
-    printf("GUI: releasing lock... %d\n", isGuiBlocked);
-#endif
-    --isGuiBlocked;
-    if (!isGuiBlocked)
-        unlock();
-}
-
-
-
-
-void QQuickCanvasRenderThread::animationStarted()
-{
-#ifdef THREAD_DEBUG
-    printf("GUI: animationStarted()\n");
-#endif
-
-    lockInGui();
-
-    animationRunning = true;
-
-    if (isRenderBlocked)
-        wake();
-
-    unlockInGui();
-}
-
-
-
-void QQuickCanvasRenderThread::animationStopped()
-{
-#ifdef THREAD_DEBUG
-    printf("GUI: animationStopped()...\n");
-#endif
-
-    lockInGui();
-    animationRunning = false;
-    unlockInGui();
-}
-
-
-void QQuickCanvasRenderThread::paint()
-{
-#ifdef THREAD_DEBUG
-    printf("GUI: paint called..\n");
-#endif
-
-    lockInGui();
-    exhaustSyncEvent();
-
-    isPaintCompleted = false;
-    while (isRunning() && !isPaintCompleted) {
-        if (isRenderBlocked)
-            wake();
-        wait();
-    }
-    unlockInGui();
-}
-
-
-
-void QQuickCanvasRenderThread::resize(const QSize &size)
-{
-#ifdef THREAD_DEBUG
-    printf("GUI: Resize Event: %dx%d\n", size.width(), size.height());
-#endif
-
-    if (!isRunning()) {
-        windowSize = size;
-        return;
-    }
-
-    lockInGui();
-    exhaustSyncEvent();
-
-    windowSize = size;
-
-    while (isRunning() && renderedSize != windowSize) {
-        if (isRenderBlocked)
-            wake();
-        wait();
-    }
-    unlockInGui();
-}
-
-
-
-void QQuickCanvasRenderThread::startRendering()
-{
-#ifdef THREAD_DEBUG
-    printf("GUI: Starting Render Thread\n");
-#endif
-    hasExited = false;
-    shouldExit = false;
-    isGuiBlocked = 0;
-    isGuiBlockPending = false;
-    start();
-}
-
-
-
-void QQuickCanvasRenderThread::stopRendering()
-{
-#ifdef THREAD_DEBUG
-    printf("GUI: stopping render thread\n");
-#endif
-
-    lockInGui();
-    exhaustSyncEvent();
-    shouldExit = true;
-
-    if (isRenderBlocked) {
-#ifdef THREAD_DEBUG
-        printf("GUI: waking up render thread\n");
-#endif
-        wake();
-    }
-
-    while (!hasExited) {
-#ifdef THREAD_DEBUG
-        printf("GUI: waiting for render thread to have exited..\n");
-#endif
-        wait();
-    }
-
-    unlockInGui();
-
-#ifdef THREAD_DEBUG
-    printf("GUI: waiting for render thread to terminate..\n");
-#endif
-    // Actually wait for the thread to terminate.  Otherwise we can delete it
-    // too early and crash.
-    QThread::wait();
-
-#ifdef THREAD_DEBUG
-    printf("GUI: thread has terminated and we're all good..\n");
-#endif
-
-}
-
-
-
-QImage QQuickCanvasRenderThread::grab()
-{
-    if (!isRunning())
-        return QImage();
-
-    if (QThread::currentThread() != qApp->thread()) {
-        qWarning("QQuickCanvas::grabFrameBuffer: can only be called from the GUI thread");
-        return QImage();
-    }
-
-#ifdef THREAD_DEBUG
-    printf("GUI: doing a pixelwise grab..\n");
-#endif
-
-    lockInGui();
-    exhaustSyncEvent();
-
-    doGrab = true;
-    isPaintCompleted = false;
-    while (isRunning() && !isPaintCompleted) {
-        if (isRenderBlocked)
-            wake();
-        wait();
-    }
-
-    QImage grabbed = grabContent;
-    grabContent = QImage();
-
-    unlockInGui();
-
-    return grabbed;
-}
-
-
-
-void QQuickCanvasRenderThread::maybeUpdate()
-{
-    Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || inSync,
-               "QQuickCanvas::update",
-               "Function can only be called from GUI thread or during QQuickItem::updatePaintNode()");
-
-    if (inSync) {
-        isExternalUpdatePending = true;
-
-    } else if (!renderThreadAwakened) {
-#ifdef THREAD_DEBUG
-        printf("GUI: doing update...\n");
-#endif
-        renderThreadAwakened = true;
-        lockInGui();
-        isExternalUpdatePending = true;
-        if (isRenderBlocked)
-            wake();
-        unlockInGui();
-    }
-}
-
-
 #include "moc_qquickcanvas.cpp"
 
 QT_END_NAMESPACE
diff --git a/src/quick/items/qquickcanvas.h b/src/quick/items/qquickcanvas.h
index 9ea73b087ba4f8055ce7a27f6997ef8503af3ac1..d38ed97028edffc80e94df255b6d55152a955681 100644
--- a/src/quick/items/qquickcanvas.h
+++ b/src/quick/items/qquickcanvas.h
@@ -90,9 +90,6 @@ public:
 
     QSGEngine *sceneGraphEngine() const;
 
-    void setVSyncAnimations(bool enabled);
-    bool vsyncAnimations() const;
-
     QImage grabFrameBuffer();
 
     void setRenderTarget(QOpenGLFramebufferObject *fbo);
@@ -115,6 +112,7 @@ public:
 Q_SIGNALS:
     void frameSwapped();
     void sceneGraphInitialized();
+    void sceneGraphInvalidated();
     void beforeRendering();
     void afterRendering();
     void clearColorChanged(const QColor &);
@@ -144,8 +142,7 @@ protected:
 
 private Q_SLOTS:
     void maybeUpdate();
-    void animationStarted();
-    void animationStopped();
+    void cleanupSceneGraph();
 
 private:
     friend class QQuickItem;
diff --git a/src/quick/items/qquickcanvas_p.h b/src/quick/items/qquickcanvas_p.h
index 633f3829543cbdb2898f75b14a47ce6b15bab382..d9d130c2805404cc852fdd97ca542a6015a95030 100644
--- a/src/quick/items/qquickcanvas_p.h
+++ b/src/quick/items/qquickcanvas_p.h
@@ -74,6 +74,8 @@ QT_BEGIN_NAMESPACE
 
 //Make it easy to identify and customize the root item if needed
 
+class QQuickWindowManager;
+
 class QQuickRootItem : public QQuickItem
 {
     Q_OBJECT
@@ -145,7 +147,6 @@ public:
     void dirtyItem(QQuickItem *);
     void cleanup(QSGNode *);
 
-    void initializeSceneGraph();
     void polishItems();
     void syncSceneGraph();
     void renderSceneGraph(const QSize &size);
@@ -166,16 +167,13 @@ public:
 
     QSGEngine *engine;
     QSGContext *context;
-    QColor clearColor;
+    QSGRenderer *renderer;
 
-    uint vsyncAnimations : 1;
-    uint clearBeforeRendering : 1;
+    QQuickWindowManager *windowManager;
 
-    QQuickCanvasRenderLoop *thread;
-    QSize widgetSize;
-    QSize viewportSize;
+    QColor clearColor;
 
-    QAnimationDriver *animationDriver;
+    uint clearBeforeRendering : 1;
 
     QOpenGLFramebufferObject *renderTarget;
 
@@ -187,134 +185,6 @@ private:
     static void cleanupNodesOnShutdown(QQuickItem *);
 };
 
-class QQuickCanvasRenderLoop
-{
-public:
-    QQuickCanvasRenderLoop()
-        : d(0)
-        , renderer(0)
-        , gl(0)
-    {
-    }
-    virtual ~QQuickCanvasRenderLoop()
-    {
-        delete gl;
-    }
-
-    friend class QQuickCanvasPrivate;
-
-    virtual void paint() = 0;
-    virtual void resize(const QSize &size) = 0;
-    virtual void startRendering() = 0;
-    virtual void stopRendering() = 0;
-    virtual QImage grab() = 0;
-    virtual void setWindowSize(const QSize &size) = 0;
-    virtual void maybeUpdate() = 0;
-    virtual bool isRunning() const = 0;
-    virtual void animationStarted() = 0;
-    virtual void animationStopped() = 0;
-    virtual void moveContextToThread(QSGContext *) { }
-    virtual bool *allowMainThreadProcessing() { return 0; }
-
-protected:
-    void initializeSceneGraph() { d->initializeSceneGraph(); }
-    void syncSceneGraph() { d->syncSceneGraph(); }
-    void cleanupNodesOnShutdown() { d->cleanupNodesOnShutdown(); }
-    void renderSceneGraph(const QSize &size) { d->renderSceneGraph(size); }
-    void polishItems() { d->polishItems(); }
-    QAnimationDriver *animationDriver() const { return d->animationDriver; }
-
-    inline QOpenGLContext *glContext() const { return gl; }
-    void createGLContext();
-    void makeCurrent() { gl->makeCurrent(renderer); }
-    void doneCurrent() { gl->doneCurrent(); }
-    void swapBuffers() {
-        gl->swapBuffers(renderer);
-        emit renderer->frameSwapped();
-    }
-
-private:
-    QQuickCanvasPrivate *d;
-    QQuickCanvas *renderer;
-
-    QOpenGLContext *gl;
-};
-
-class QQuickCanvasRenderThread : public QThread, public QQuickCanvasRenderLoop
-{
-    Q_OBJECT
-public:
-    QQuickCanvasRenderThread()
-        : mutex(QMutex::NonRecursive)
-        , allowMainThreadProcessingFlag(true)
-        , animationRunning(false)
-        , isGuiBlocked(0)
-        , isPaintCompleted(false)
-        , isGuiBlockPending(false)
-        , isRenderBlocked(false)
-        , isExternalUpdatePending(false)
-        , syncAlreadyHappened(false)
-        , inSync(false)
-        , doGrab(false)
-        , shouldExit(false)
-        , hasExited(false)
-        , renderThreadAwakened(false)
-    {}
-
-    inline void lock() { mutex.lock(); }
-    inline void unlock() { mutex.unlock(); }
-    inline void wait() { condition.wait(&mutex); }
-    inline void wake() { condition.wakeOne(); }
-
-    void lockInGui();
-    void unlockInGui();
-
-    void paint();
-    void resize(const QSize &size);
-    void startRendering();
-    void stopRendering();
-    void exhaustSyncEvent();
-    void sync(bool guiAlreadyLocked);
-    bool isRunning() const { return QThread::isRunning(); }
-    void setWindowSize(const QSize &size) { windowSize = size; }
-    void maybeUpdate();
-    void moveContextToThread(QSGContext *c) { c->moveToThread(this); }
-    bool *allowMainThreadProcessing() { return &allowMainThreadProcessingFlag; }
-
-    bool event(QEvent *);
-
-    QImage grab();
-
-public slots:
-    void animationStarted();
-    void animationStopped();
-
-public:
-    QMutex mutex;
-    QWaitCondition condition;
-
-    bool allowMainThreadProcessingFlag;
-
-    QSize windowSize;
-    QSize renderedSize;
-
-    uint animationRunning: 1;
-    int isGuiBlocked;
-    uint isPaintCompleted : 1;
-    uint isGuiBlockPending : 1;
-    uint isRenderBlocked : 1;
-    uint isExternalUpdatePending : 1;
-    uint syncAlreadyHappened : 1;
-    uint inSync : 1;
-    uint doGrab : 1;
-    uint shouldExit : 1;
-    uint hasExited : 1;
-    uint renderThreadAwakened : 1;
-
-    QImage grabContent;
-
-    void run();
-};
 
 Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickCanvasPrivate::FocusOptions)
 
diff --git a/src/quick/items/qquickwindowmanager.cpp b/src/quick/items/qquickwindowmanager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c6baf13758f6e4f263c452f12c081a2a7bba6680
--- /dev/null
+++ b/src/quick/items/qquickwindowmanager.cpp
@@ -0,0 +1,1242 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickwindowmanager_p.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QTime>
+#include <QtCore/QMutex>
+#include <QtCore/QWaitCondition>
+#include <QtCore/private/qabstractanimation_p.h>
+
+#include <QtGui/QOpenGLContext>
+#include <QtGui/private/qguiapplication_p.h>
+
+#include <QtDeclarative/private/qdeclarativeglobal_p.h>
+
+#include <QtQuick/QQuickCanvas>
+#include <QtQuick/private/qquickcanvas_p.h>
+#include <QtQuick/private/qsgcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+
+#define QQUICK_CANVAS_TIMING
+#ifdef QQUICK_CANVAS_TIMING
+static bool qquick_canvas_timing = !qgetenv("QML_CANVAS_TIMING").isEmpty();
+static QTime threadTimer;
+static int syncTime;
+static int renderTime;
+static int swapTime;
+#endif
+
+extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
+
+
+
+/*!
+    expectations for this manager to work:
+     - one opengl context to render multiple windows
+     - OpenGL pipeline will not block for vsync in swap
+     - OpenGL pipeline will block based on a full buffer queue.
+     - Multiple screens can share the OpenGL context
+     - Animations are advanced for all windows once per swap
+ */
+
+/*
+  Threaded Rendering
+  ==================
+
+  The threaded rendering uses a number of different variables to track potential
+  states used to handle resizing, initial paint, grabbing and driving animations
+  while ALWAYS keeping the GL context in the rendering thread and keeping the
+  overhead of normal one-shot paints and vblank driven animations at a minimum.
+
+  Resize, initial show and grab suffer slightly in this model as they are locked
+  to the rendering in the rendering thread, but this is a necessary evil for
+  the system to work.
+
+  Variables that are used:
+
+  Private::animationRunning: This is true while the animations are running, and only
+  written to inside locks.
+
+  RenderThread::isGuiLocked: This is used to indicate that the GUI thread owns the
+  lock. This variable is an integer to allow for recursive calls to lockInGui()
+  without using a recursive mutex. See isPostingSyncEvent.
+
+  RenderThread::isPaintComplete: This variable is cleared when rendering starts and
+  set once rendering is complete. It is monitored in the paintEvent(),
+  resizeEvent() and grab() functions to force them to wait for rendering to
+  complete.
+
+  RenderThread::isPostingSyncEvent: This variable is set in the render thread just
+  before the sync event is sent to the GUI thread. It is used to avoid deadlocks
+  in the case where render thread waits while waiting for GUI to pick up the sync
+  event and GUI thread gets a resizeEvent, the initial paintEvent or a grab.
+  When this happens, we use the
+  exhaustSyncEvent() function to do the sync right there and mark the coming
+  sync event to be discarded. There can only ever be one sync incoming.
+
+  RenderThread::isRenderBlock: This variable is true when animations are not
+  running and the render thread has gone to sleep, waiting for more to do.
+
+  RenderThread::isExternalUpdatePending: This variable is set to false when
+  a new render pass is started and to true in maybeUpdate(). It is an
+  indication to the render thread that another render pass needs to take
+  place, rather than the render thread going to sleep after completing its swap.
+
+  RenderThread::doGrab: This variable is set by the grab() function and
+  tells the renderer to do a grab after rendering is complete and before
+  swapping happens.
+
+  RenderThread::shouldExit: This variable is used to determine if the render
+  thread should do a nother pass. It is typically set as a result of show()
+  and unset as a result of hide() or during shutdown()
+
+  RenderThread::hasExited: Used by the GUI thread to synchronize the shutdown
+  after shouldExit has been set to true.
+ */
+
+DEFINE_BOOL_CONFIG_OPTION(qmlFixedAnimationStep, QML_FIXED_ANIMATION_STEP);
+DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_BAD_GUI_RENDER_LOOP);
+
+//#define THREAD_DEBUG
+
+class QQuickRenderThreadSingleContextWindowManager : public QThread, public QQuickWindowManager
+{
+    Q_OBJECT
+public:
+    QQuickRenderThreadSingleContextWindowManager()
+        : sg(QSGContext::createDefaultContext())
+        , gl(0)
+        , animationTimer(-1)
+        , isGuiLocked(0)
+        , animationRunning(false)
+        , isPaintCompleted(false)
+        , isPostingSyncEvent(false)
+        , isRenderBlocked(false)
+        , syncAlreadyHappened(false)
+        , inSync(false)
+        , shouldExit(false)
+        , hasExited(false)
+        , renderThreadAwakened(false)
+        , canvasToGrab(0)
+    {
+        sg->moveToThread(this);
+
+        animationDriver = sg->createAnimationDriver(this);
+        animationDriver->install();
+        connect(animationDriver, SIGNAL(started()), this, SLOT(animationStarted()));
+        connect(animationDriver, SIGNAL(stopped()), this, SLOT(animationStopped()));
+    }
+
+    QSGContext *sceneGraphContext() const { return sg; }
+
+    void show(QQuickCanvas *canvas);
+    void hide(QQuickCanvas *canvas);
+
+    void canvasDestroyed(QQuickCanvas *canvas);
+
+    void paint(QQuickCanvas *canvas);
+    QImage grab(QQuickCanvas *canvas);
+    void resize(QQuickCanvas *canvas, const QSize &size);
+    void maybeUpdate(QQuickCanvas *canvas);
+
+    void startRendering();
+    void stopRendering();
+
+    void exhaustSyncEvent();
+    void sync(bool guiAlreadyLocked);
+
+    void initialize();
+
+    bool *allowMainThreadProcessing() { return &allowMainThreadProcessingFlag; }
+
+    bool event(QEvent *);
+
+    inline void lock() { mutex.lock(); }
+    inline void unlock() { mutex.unlock(); }
+    inline void wait() { condition.wait(&mutex); }
+    inline void wake() { condition.wakeOne(); }
+    void lockInGui();
+    void unlockInGui();
+
+    void run();
+
+public slots:
+    void animationStarted();
+    void animationStopped();
+    void canvasVisibilityChanged();
+
+private:
+    void handleAddedWindows();
+    void handleAddedWindow(QQuickCanvas *canvas);
+    void handleRemovedWindows();
+
+    QSGContext *sg;
+    QOpenGLContext *gl;
+    QAnimationDriver *animationDriver;
+    int animationTimer;
+
+    QMutex mutex;
+    QWaitCondition condition;
+
+    bool allowMainThreadProcessingFlag;
+
+    int isGuiLocked;
+    uint animationRunning: 1;
+    uint isPaintCompleted : 1;
+    uint isPostingSyncEvent : 1;
+    uint isRenderBlocked : 1;
+    uint isExternalUpdatePending : 1;
+    uint syncAlreadyHappened : 1;
+    uint inSync : 1;
+    uint shouldExit : 1;
+    uint hasExited : 1;
+    uint renderThreadAwakened : 1;
+    uint isGuiAboutToBeBlockedForSync : 1;
+
+    QQuickCanvas *canvasToGrab;
+    QImage grabContent;
+
+    struct CanvasData {
+        QSize renderedSize;
+        QSize windowSize;
+        QSize viewportSize;
+
+        uint sizeWasChanged : 1;
+        uint isExternalUpdatePending : 1;
+    };
+
+    QHash<QQuickCanvas *, CanvasData *> m_rendered_windows;
+
+    struct CanvasTracker {
+        QQuickCanvas *canvas;
+        uint isVisible : 1;
+        uint toBeRemoved : 1;
+    };
+
+    QList<CanvasTracker> m_tracked_windows;
+
+    QList<QQuickCanvas *> m_removed_windows;
+    QList<QQuickCanvas *> m_added_windows;
+};
+
+
+class QQuickTrivialWindowManager : public QObject, public QQuickWindowManager
+{
+public:
+    QQuickTrivialWindowManager();
+
+    void show(QQuickCanvas *canvas);
+    void hide(QQuickCanvas *canvas);
+
+    void canvasDestroyed(QQuickCanvas *canvas);
+
+    void renderCanvas(QQuickCanvas *canvas);
+    void paint(QQuickCanvas *canvas);
+    QImage grab(QQuickCanvas *canvas);
+    void resize(QQuickCanvas *canvas, const QSize &size);
+
+    void maybeUpdate(QQuickCanvas *canvas);
+
+    bool *allowMainThreadProcessing();
+
+    QSGContext *sceneGraphContext() const;
+
+    bool event(QEvent *);
+
+    struct CanvasData {
+        bool updatePending : 1;
+        bool grabOnly : 1;
+    };
+
+    QHash<QQuickCanvas *, CanvasData> m_windows;
+
+    QOpenGLContext *gl;
+    QSGContext *sg;
+
+    QImage grabContent;
+
+    bool eventPending;
+};
+
+
+QQuickWindowManager *QQuickWindowManager::instance()
+{
+    static QQuickWindowManager *theInstance;
+
+    if (!theInstance) {
+        bool fancy = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL);
+        if (qmlNoThreadedRenderer())
+            fancy = false;
+        if (qmlFixedAnimationStep())
+            QUnifiedTimer::instance(true)->setConsistentTiming(true);
+        theInstance = fancy
+                ? (QQuickWindowManager*) new QQuickRenderThreadSingleContextWindowManager
+                : (QQuickWindowManager*) new QQuickTrivialWindowManager;
+    }
+    return theInstance;
+}
+
+
+
+
+
+void QQuickRenderThreadSingleContextWindowManager::initialize()
+{
+    Q_ASSERT(m_rendered_windows.size());
+    QQuickCanvas *win = m_rendered_windows.constBegin().key();
+
+    gl = new QOpenGLContext();
+    // Pick up the surface format from one of them
+    gl->setFormat(win->requestedFormat());
+    gl->create();
+    gl->makeCurrent(win);
+
+    Q_ASSERT(!sg->isReady());
+    sg->initialize(gl);
+}
+
+
+/*!
+    This function is called when the canvas is created to register the canvas with
+    the window manager.
+
+    Called on GUI Thread.
+ */
+
+void QQuickRenderThreadSingleContextWindowManager::show(QQuickCanvas *canvas)
+{
+#ifdef THREAD_DEBUG
+    printf("GUI: Canvas added to windowing system, %p, %dx%d\n", canvas, canvas->width(), canvas->height());
+#endif
+
+    CanvasTracker tracker;
+    tracker.canvas = canvas;
+    tracker.isVisible = false;
+    tracker.toBeRemoved = false;
+    m_tracked_windows << tracker;
+
+    connect(canvas, SIGNAL(widthChanged(int)), this, SLOT(canvasVisibilityChanged()), Qt::DirectConnection);
+    connect(canvas, SIGNAL(heightChanged(int)), this, SLOT(canvasVisibilityChanged()), Qt::DirectConnection);
+
+    canvasVisibilityChanged();
+}
+
+
+void QQuickRenderThreadSingleContextWindowManager::handleAddedWindow(QQuickCanvas *canvas)
+{
+#ifdef THREAD_DEBUG
+    printf("                RenderThread: adding canvas: %p\n", canvas);
+#endif
+
+    CanvasData *data = new CanvasData;
+    data->isExternalUpdatePending = true;
+    data->sizeWasChanged = false;
+    data->windowSize = canvas->size();
+    m_rendered_windows[canvas] = data;
+}
+
+
+/*!
+    Called on Render Thread
+ */
+void QQuickRenderThreadSingleContextWindowManager::handleAddedWindows()
+{
+#ifdef THREAD_DEBUG
+    printf("                RenderThread: about to add %d\n", m_added_windows.size());
+#endif
+
+    while (m_added_windows.size()) {
+        QQuickCanvas *canvas = m_added_windows.takeLast();
+        handleAddedWindow(canvas);
+    }
+}
+
+
+/*!
+    Called on the GUI Thread, from the canvas' destructor
+ */
+
+void QQuickRenderThreadSingleContextWindowManager::canvasDestroyed(QQuickCanvas *canvas)
+{
+#ifdef THREAD_DEBUG
+    printf("GUI: Canvas destroyed: %p\n", canvas);
+#endif
+
+    hide(canvas);
+}
+
+
+/*!
+    Called on GUI Thread
+ */
+
+void QQuickRenderThreadSingleContextWindowManager::hide(QQuickCanvas *canvas)
+{
+#ifdef THREAD_DEBUG
+    printf("GUI: Canvas hidden: %p\n", canvas);
+#endif
+
+    int position = -1;
+    for (int i=0; i<m_tracked_windows.size(); ++i) {
+        if (m_tracked_windows.at(i).canvas == canvas) {
+            m_tracked_windows[i].toBeRemoved = true;
+            position = i;
+            break;
+        }
+    }
+
+    if (position >= 0) {
+        disconnect(canvas, SIGNAL(widthChanged(int)), this, SLOT(canvasVisibilityChanged()));
+        disconnect(canvas, SIGNAL(heightChanged(int)), this, SLOT(canvasVisibilityChanged()));
+        canvasVisibilityChanged();
+        m_tracked_windows.removeAt(position);
+    }
+
+#ifdef THREAD_DEBUG
+    printf("GUI: Canvas removal completed... %p\n", canvas);
+#endif
+}
+
+/*!
+    Called on Render Thread
+ */
+void QQuickRenderThreadSingleContextWindowManager::handleRemovedWindows()
+{
+#ifdef THREAD_DEBUG
+    printf("                RenderThread: about to remove %d\n", m_removed_windows.size());
+#endif
+
+    bool removedAnything = false;
+    while (m_removed_windows.size()) {
+        QQuickCanvas *canvas = m_removed_windows.takeLast();
+#ifdef THREAD_DEBUG
+    printf("            RenderThread: removing %p\n", canvas);
+#endif
+
+        QQuickCanvasPrivate::get(canvas)->cleanupNodesOnShutdown();
+        delete m_rendered_windows.take(canvas);
+        removedAnything = true;
+    }
+
+    // If a window is removed because it has been hidden it will take with it
+    // the gl context (at least on Mac) if bound, so disconnect the gl context
+    // from anything
+    if (removedAnything)
+        gl->doneCurrent();
+}
+
+
+
+/*!
+    Called on GUI Thread
+ */
+
+void QQuickRenderThreadSingleContextWindowManager::canvasVisibilityChanged()
+{
+    bool anyoneShowing = false;
+    QList<QQuickCanvas *> toAdd, toRemove;
+
+    // Not optimal, but also not frequently used...
+    for (int i=0; i<m_tracked_windows.size(); ++i) {
+        CanvasTracker &t = const_cast<CanvasTracker &>(m_tracked_windows.at(i));
+        QQuickCanvas *win = t.canvas;
+
+        Q_ASSERT(win->visible() || t.toBeRemoved);
+        bool canvasVisible = win->width() > 0 && win->height() > 0;
+        anyoneShowing |= (canvasVisible && !t.toBeRemoved);
+
+        if ((!canvasVisible && t.isVisible) || t.toBeRemoved) {
+            toRemove << win;
+        } else if (canvasVisible && !t.isVisible) {
+            toAdd << win;
+        }
+        t.isVisible = canvasVisible;
+    }
+
+    if (isRunning()) {
+        if (!anyoneShowing) {
+            stopRendering();
+        } else {
+            lockInGui();
+            exhaustSyncEvent();
+            m_added_windows << toAdd;
+            m_removed_windows << toRemove;
+            while (isRunning() && (m_added_windows.size() || m_removed_windows.size())) {
+                if (isRenderBlocked)
+                    wake();
+                wait();
+            }
+            unlockInGui();
+        }
+
+    } else if (anyoneShowing) {
+        Q_ASSERT(toRemove.isEmpty()); // since loop is not running, nothing is showing now
+        for (int i=0; i<toAdd.size(); ++i)
+            handleAddedWindow(toAdd.at(i));
+        startRendering();
+    }
+
+}
+
+
+void QQuickRenderThreadSingleContextWindowManager::run()
+{
+#ifdef THREAD_DEBUG
+    printf("QML Rendering Thread Started\n");
+#endif
+
+    if (!gl)
+        initialize();
+
+    while (!shouldExit) {
+        lock();
+
+#ifdef THREAD_DEBUG
+        printf("                RenderThread: *** NEW FRAME ***\n");
+#endif
+
+        handleAddedWindows();
+
+        if (!isGuiLocked) {
+            isPostingSyncEvent = true;
+
+#ifdef THREAD_DEBUG
+            printf("                RenderThread: aquired sync lock...\n");
+#endif
+            allowMainThreadProcessingFlag = false;
+            QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+
+#ifdef THREAD_DEBUG
+            printf("                RenderThread: going to sleep...\n");
+#endif
+            wake(); // In case the event got through all the way to wait() before this thread got to wait.
+            wait();
+
+
+            isPostingSyncEvent = false;
+        }
+
+#ifdef THREAD_DEBUG
+        printf("                RenderThread: Doing locked sync\n");
+#endif
+#ifdef QQUICK_CANVAS_TIMING
+        if (qquick_canvas_timing)
+            threadTimer.start();
+#endif
+        inSync = true;
+        for (QHash<QQuickCanvas *, CanvasData *>::const_iterator it = m_rendered_windows.constBegin();
+             it != m_rendered_windows.constEnd(); ++it) {
+            QQuickCanvas *canvas = it.key();
+
+#ifdef THREAD_DEBUG
+            printf("                RenderThread: Syncing canvas: %p\n", canvas);
+#endif
+
+            CanvasData *canvasData = it.value();
+            QQuickCanvasPrivate *canvasPrivate = QQuickCanvasPrivate::get(canvas);
+
+            Q_ASSERT(canvasData->windowSize.width() > 0 && canvasData->windowSize.height() > 0);
+
+            gl->makeCurrent(canvas);
+
+            if (canvasData->viewportSize != canvasData->windowSize) {
+#ifdef THREAD_DEBUG
+                printf("                RenderThread: --- window has changed size...\n");
+#endif
+                canvasData->viewportSize = canvasData->windowSize;
+                canvasData->sizeWasChanged = true;
+                glViewport(0, 0, canvasData->viewportSize.width(), canvasData->viewportSize.height());
+            }
+
+            canvasData->isExternalUpdatePending = false;
+            canvasPrivate->syncSceneGraph();
+        }
+        inSync = false;
+
+        // Wake GUI after sync to let it continue animating and event processing.
+        allowMainThreadProcessingFlag = true;
+        wake();
+        unlock();
+#ifdef THREAD_DEBUG
+        printf("                RenderThread: sync done\n");
+#endif
+#ifdef QQUICK_CANVAS_TIMING
+        if (qquick_canvas_timing)
+            syncTime = threadTimer.elapsed();
+#endif
+
+        for (QHash<QQuickCanvas *, CanvasData *>::const_iterator it = m_rendered_windows.constBegin();
+             it != m_rendered_windows.constEnd(); ++it) {
+            QQuickCanvas *canvas = it.key();
+            CanvasData *canvasData = it.value();
+            QQuickCanvasPrivate *canvasPrivate = QQuickCanvasPrivate::get(canvas);
+
+#ifdef THREAD_DEBUG
+            printf("                RenderThread: Rendering canvas %p\n", canvas);
+#endif
+
+            Q_ASSERT(canvasData->windowSize.width() > 0 && canvasData->windowSize.height() > 0);
+
+#ifdef THREAD_DEBUG
+            printf("                RenderThread: --- rendering at size %dx%d\n",
+                   canvasData->viewportSize.width(), canvasData->viewportSize.height()
+                   );
+#endif
+
+            // We only need to re-makeCurrent when we have multiple surfaces.
+            if (m_rendered_windows.size() > 1)
+                gl->makeCurrent(canvas);
+
+            canvasPrivate->renderSceneGraph(canvasData->viewportSize);
+#ifdef QQUICK_CANVAS_TIMING
+            if (qquick_canvas_timing)
+                renderTime = threadTimer.elapsed() - syncTime;
+#endif
+
+            // The content of the target buffer is undefined after swap() so grab needs
+            // to happen before swap();
+            if (canvas == canvasToGrab) {
+#ifdef THREAD_DEBUG
+                printf("                RenderThread: --- grabbing...\n");
+#endif
+                grabContent = qt_gl_read_framebuffer(canvasData->windowSize, false, false);
+                canvasToGrab = 0;
+            }
+
+#ifdef THREAD_DEBUG
+            printf("                RenderThread: --- wait for swap...\n");
+#endif
+
+            gl->swapBuffers(canvas);
+#ifdef THREAD_DEBUG
+            printf("                RenderThread: --- swap complete...\n");
+#endif
+
+        }
+
+#ifdef QQUICK_CANVAS_TIMING
+            if (qquick_canvas_timing) {
+                swapTime = threadTimer.elapsed() - renderTime;
+                qDebug() << "- Breakdown of frame time; sync:" << syncTime
+                         << "ms render:" << renderTime << "ms swap:" << swapTime
+                         << "ms total:" << swapTime + renderTime << "ms";
+            }
+#endif
+
+        lock();
+
+        handleRemovedWindows();
+
+        isPaintCompleted = true;
+
+        bool isExternalUpdatePending = false;
+
+        // Update sizes...
+        for (QHash<QQuickCanvas *, CanvasData *>::const_iterator it = m_rendered_windows.constBegin();
+             it != m_rendered_windows.constEnd(); ++it) {
+            CanvasData *canvasData = it.value();
+            if (canvasData->sizeWasChanged) {
+                canvasData->renderedSize = canvasData->viewportSize;
+                canvasData->sizeWasChanged = false;
+            }
+            isExternalUpdatePending |= canvasData->isExternalUpdatePending;
+        }
+
+
+        // Wake the GUI thread now that rendering is complete, to signal that painting
+        // is done, resizing is done or grabbing is completed. For grabbing, we're
+        // signalling this much later than needed (we could have done it before swap)
+        // but we don't want to lock an extra time.
+        wake();
+
+        if (!animationRunning && !isExternalUpdatePending && !shouldExit && !canvasToGrab) {
+#ifdef THREAD_DEBUG
+            printf("                RenderThread: nothing to do, going to sleep...\n");
+#endif
+            isRenderBlocked = true;
+            wait();
+            isRenderBlocked = false;
+        }
+
+        unlock();
+
+        QCoreApplication::processEvents();
+
+        // Process any "deleteLater" objects...
+        QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+    }
+
+#ifdef THREAD_DEBUG
+    printf("                RenderThread: deleting all outstanding nodes\n");
+#endif
+
+    m_removed_windows << m_rendered_windows.keys();
+    handleRemovedWindows();
+
+    sg->invalidate();
+
+    gl->doneCurrent();
+    delete gl;
+    gl = 0;
+
+#ifdef THREAD_DEBUG
+    printf("                RenderThread: render loop exited... Good Night!\n");
+#endif
+
+    lock();
+    hasExited = true;
+
+#ifdef THREAD_DEBUG
+    printf("                RenderThread: waking GUI for final sleep..\n");
+#endif
+    wake();
+    unlock();
+
+#ifdef THREAD_DEBUG
+    printf("                RenderThread: All done...\n");
+#endif
+}
+
+bool QQuickRenderThreadSingleContextWindowManager::event(QEvent *e)
+{
+    Q_ASSERT(QThread::currentThread() == qApp->thread());
+
+    if (e->type() == QEvent::User) {
+
+        // If all canvases have been hidden, ignore the event
+        if (!isRunning())
+            return true;
+
+        if (!syncAlreadyHappened)
+            sync(false);
+
+        syncAlreadyHappened = false;
+
+        if (animationRunning) {
+#ifdef THREAD_DEBUG
+            printf("GUI: Advancing animations...\n");
+#endif
+
+            animationDriver->advance();
+
+#ifdef THREAD_DEBUG
+            printf("GUI: Animations advanced...\n");
+#endif
+        }
+
+        return true;
+
+    } else if (e->type() == QEvent::Timer) {
+#ifdef THREAD_DEBUG
+            printf("GUI: Animations advanced via timer...\n");
+#endif
+        animationDriver->advance();
+    }
+
+    return QThread::event(e);
+}
+
+
+
+void QQuickRenderThreadSingleContextWindowManager::exhaustSyncEvent()
+{
+    if (isPostingSyncEvent) {
+        sync(true);
+        syncAlreadyHappened = true;
+    }
+}
+
+
+
+void QQuickRenderThreadSingleContextWindowManager::sync(bool guiAlreadyLocked)
+{
+#ifdef THREAD_DEBUG
+    printf("GUI: sync - %s\n", guiAlreadyLocked ? "outside event" : "inside event");
+#endif
+    if (!guiAlreadyLocked)
+        lockInGui();
+
+    renderThreadAwakened = false;
+
+    for (QHash<QQuickCanvas *, CanvasData *>::const_iterator it = m_rendered_windows.constBegin();
+         it != m_rendered_windows.constEnd(); ++it) {
+        QQuickCanvasPrivate::get(it.key())->polishItems();
+    }
+
+    wake();
+    wait();
+
+    if (!guiAlreadyLocked)
+        unlockInGui();
+}
+
+
+
+
+/*!
+    Acquires the mutex for the GUI thread. The function uses the isGuiLocked
+    variable to keep track of how many recursion levels the gui is locked with.
+    We only actually acquire the mutex for the first level to avoid deadlocking
+    ourselves.
+ */
+
+void QQuickRenderThreadSingleContextWindowManager::lockInGui()
+{
+    if (++isGuiLocked == 1)
+        lock();
+
+#ifdef THREAD_DEBUG
+    printf("GUI: aquired lock... level=%d\n", isGuiLocked);
+#endif
+}
+
+
+
+void QQuickRenderThreadSingleContextWindowManager::unlockInGui()
+{
+#ifdef THREAD_DEBUG
+    printf("GUI: releasing lock... level=%d\n", isGuiLocked);
+#endif
+
+    if (--isGuiLocked == 0)
+        unlock();
+}
+
+
+
+
+void QQuickRenderThreadSingleContextWindowManager::animationStarted()
+{
+#ifdef THREAD_DEBUG
+    printf("GUI: animationStarted()\n");
+#endif
+
+    if (!isRunning()) {
+        animationTimer = startTimer(1000/60);
+        return;
+    }
+
+    lockInGui();
+
+    animationRunning = true;
+
+    if (isRenderBlocked)
+        wake();
+
+    unlockInGui();
+}
+
+
+
+void QQuickRenderThreadSingleContextWindowManager::animationStopped()
+{
+#ifdef THREAD_DEBUG
+    printf("GUI: animationStopped()...\n");
+#endif
+
+    if (!isRunning()) {
+        killTimer(animationTimer);
+        animationTimer = -1;
+        return;
+    }
+
+    lockInGui();
+    animationRunning = false;
+    unlockInGui();
+}
+
+
+void QQuickRenderThreadSingleContextWindowManager::paint(QQuickCanvas *canvas)
+{
+    Q_UNUSED(canvas);
+#ifdef THREAD_DEBUG
+    printf("GUI: paint called: %p\n", canvas);
+#endif
+
+    return;
+
+
+
+    lockInGui();
+    exhaustSyncEvent();
+
+    isPaintCompleted = false;
+    while (isRunning() && !isPaintCompleted) {
+        if (isRenderBlocked)
+            wake();
+        wait();
+    }
+    unlockInGui();
+
+#ifdef THREAD_DEBUG
+    printf("GUI: paint done: %p\n", canvas);
+#endif
+}
+
+
+
+void QQuickRenderThreadSingleContextWindowManager::resize(QQuickCanvas *canvas, const QSize &size)
+{
+#ifdef THREAD_DEBUG
+    printf("GUI: Resize Event: %p = %dx%d\n", canvas, size.width(), size.height());
+#endif
+
+    // If the rendering thread is not running we do not need to do anything.
+    // Also if the canvas is being resized to an invalid size, it will be removed
+    // by the canvasVisibilityChanged slot as result of width/heightcChanged()
+    if (!isRunning() || size.width() <= 0 || size.height() <= 0)
+        return;
+
+    lockInGui();
+    exhaustSyncEvent();
+
+    CanvasData *canvasData = m_rendered_windows.value(canvas);
+    if (canvasData) {
+        canvasData->windowSize = size;
+        while (isRunning() && canvasData->renderedSize != size && size.width() > 0 && size.height() > 0) {
+            if (isRenderBlocked)
+                wake();
+            wait();
+        }
+    }
+    unlockInGui();
+
+#ifdef THREAD_DEBUG
+    printf("GUI: Resize done: %p\n", canvas);
+#endif
+}
+
+
+
+void QQuickRenderThreadSingleContextWindowManager::startRendering()
+{
+#ifdef THREAD_DEBUG
+    printf("GUI: Starting Render Thread\n");
+#endif
+    hasExited = false;
+    shouldExit = false;
+    isGuiLocked = 0;
+    isPostingSyncEvent = false;
+    syncAlreadyHappened = false;
+    renderThreadAwakened = false;
+    inSync = false;
+
+    start(); // Start the render thread...
+
+    // Animations will now be driven from the rendering thread.
+    if (animationTimer >= 0) {
+        killTimer(animationTimer);
+        animationTimer = -1;
+    }
+
+
+}
+
+
+
+void QQuickRenderThreadSingleContextWindowManager::stopRendering()
+{
+#ifdef THREAD_DEBUG
+    printf("GUI: stopping render thread\n");
+#endif
+
+    lockInGui();
+    exhaustSyncEvent();
+    shouldExit = true;
+
+    if (isRenderBlocked) {
+#ifdef THREAD_DEBUG
+        printf("GUI: waking up render thread\n");
+#endif
+        wake();
+    }
+
+    while (!hasExited) {
+#ifdef THREAD_DEBUG
+        printf("GUI: waiting for render thread to have exited..\n");
+#endif
+        wait();
+    }
+
+    unlockInGui();
+
+#ifdef THREAD_DEBUG
+    printf("GUI: waiting for render thread to terminate..\n");
+#endif
+    // Actually wait for the thread to terminate.  Otherwise we can delete it
+    // too early and crash.
+    QThread::wait();
+
+#ifdef THREAD_DEBUG
+    printf("GUI: thread has terminated and we're all good..\n");
+#endif
+
+    // Activate timer to keep animations running
+    if (animationDriver->isRunning())
+        animationTimer = startTimer(1000/60);
+}
+
+
+
+QImage QQuickRenderThreadSingleContextWindowManager::grab(QQuickCanvas *canvas)
+{
+    if (!isRunning())
+        return QImage();
+
+    if (QThread::currentThread() != qApp->thread()) {
+        qWarning("QQuickCanvas::grabFrameBuffer: can only be called from the GUI thread");
+        return QImage();
+    }
+
+#ifdef THREAD_DEBUG
+    printf("GUI: doing a pixelwise grab..\n");
+#endif
+
+    lockInGui();
+    exhaustSyncEvent();
+
+    canvasToGrab = canvas;
+    isPaintCompleted = false;
+    while (isRunning() && !isPaintCompleted) {
+        if (isRenderBlocked)
+            wake();
+        wait();
+    }
+
+    QImage grabbed = grabContent;
+    grabContent = QImage();
+
+    unlockInGui();
+
+    return grabbed;
+}
+
+
+
+void QQuickRenderThreadSingleContextWindowManager::maybeUpdate(QQuickCanvas *canvas)
+{
+    Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || inSync,
+               "QQuickCanvas::update",
+               "Function can only be called from GUI thread or during QQuickItem::updatePaintNode()");
+
+    if (inSync) {
+        CanvasData *canvasData = m_rendered_windows.value(canvas);
+        if (canvasData)
+            canvasData->isExternalUpdatePending = true;
+
+    } else if (!renderThreadAwakened) {
+#ifdef THREAD_DEBUG
+        printf("GUI: doing update...\n");
+#endif
+        renderThreadAwakened = true;
+        bool locked = false;
+
+        // If we are getting here from the renderer's sync event, the renderer is about
+        // to go to sleep anyway.
+        if (!isGuiAboutToBeBlockedForSync)
+            lockInGui();
+        CanvasData *canvasData = m_rendered_windows.value(canvas);
+        if (canvasData)
+            canvasData->isExternalUpdatePending = true;
+        if (isRenderBlocked)
+            wake();
+        if (!isGuiAboutToBeBlockedForSync)
+            unlockInGui();
+    }
+}
+
+QQuickTrivialWindowManager::QQuickTrivialWindowManager()
+    : gl(0)
+    , eventPending(false)
+{
+    sg = QSGContext::createDefaultContext();
+}
+
+
+void QQuickTrivialWindowManager::show(QQuickCanvas *canvas)
+{
+    CanvasData data;
+    data.updatePending = false;
+    m_windows[canvas] = data;
+
+    maybeUpdate(canvas);
+}
+
+void QQuickTrivialWindowManager::hide(QQuickCanvas *canvas)
+{
+    if (!m_windows.contains(canvas))
+        return;
+
+    m_windows.remove(canvas);
+    QQuickCanvasPrivate *cd = QQuickCanvasPrivate::get(canvas);
+    cd->cleanupNodesOnShutdown();
+
+    if (m_windows.size() == 0) {
+        sg->invalidate();
+        delete gl;
+        gl = 0;
+    }
+}
+
+void QQuickTrivialWindowManager::canvasDestroyed(QQuickCanvas *canvas)
+{
+    hide(canvas);
+}
+
+void QQuickTrivialWindowManager::renderCanvas(QQuickCanvas *canvas)
+{
+    if (!m_windows.contains(canvas))
+        return;
+
+    CanvasData &data = const_cast<CanvasData &>(m_windows[canvas]);
+
+    if (!gl) {
+        gl = new QOpenGLContext();
+        gl->setFormat(canvas->requestedFormat());
+        gl->create();
+        gl->makeCurrent(canvas);
+        sg->initialize(gl);
+    } else {
+        gl->makeCurrent(canvas);
+    }
+
+    bool alsoSwap = data.updatePending;
+    data.updatePending = false;
+
+    QQuickCanvasPrivate *cd = QQuickCanvasPrivate::get(canvas);
+    cd->polishItems();
+    cd->syncSceneGraph();
+    cd->renderSceneGraph(canvas->size());
+
+    if (data.grabOnly) {
+        grabContent = qt_gl_read_framebuffer(canvas->size(), false, false);
+        data.grabOnly = false;
+    }
+
+    if (alsoSwap)
+        gl->swapBuffers(canvas);
+
+    // Might have been set during syncSceneGraph()
+    if (data.updatePending)
+        maybeUpdate(canvas);
+}
+
+void QQuickTrivialWindowManager::paint(QQuickCanvas *canvas)
+{
+    if (!m_windows.contains(canvas))
+        return;
+
+    m_windows[canvas].updatePending = true;
+    renderCanvas(canvas);
+}
+
+QImage QQuickTrivialWindowManager::grab(QQuickCanvas *canvas)
+{
+    if (!m_windows.contains(canvas))
+        return QImage();
+
+    m_windows[canvas].grabOnly = true;
+
+    renderCanvas(canvas);
+
+    QImage grabbed = grabContent;
+    grabContent = QImage();
+    return grabbed;
+}
+
+
+
+void QQuickTrivialWindowManager::resize(QQuickCanvas *, const QSize &)
+{
+}
+
+
+
+void QQuickTrivialWindowManager::maybeUpdate(QQuickCanvas *canvas)
+{
+    if (!m_windows.contains(canvas))
+        return;
+
+    m_windows[canvas].updatePending = true;
+
+    if (!eventPending) {
+        QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+        eventPending = true;
+    }
+}
+
+
+
+bool *QQuickTrivialWindowManager::allowMainThreadProcessing()
+{
+    return 0;
+}
+
+
+
+QSGContext *QQuickTrivialWindowManager::sceneGraphContext() const
+{
+    return sg;
+}
+
+
+bool QQuickTrivialWindowManager::event(QEvent *e)
+{
+    if (e->type() == QEvent::User) {
+        eventPending = false;
+        for (QHash<QQuickCanvas *, CanvasData>::const_iterator it = m_windows.constBegin();
+             it != m_windows.constEnd(); ++it) {
+            const CanvasData &data = it.value();
+            if (data.updatePending)
+                renderCanvas(it.key());
+        }
+        return true;
+    }
+    return QObject::event(e);
+}
+
+#include "qquickwindowmanager.moc"
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindowmanager_p.h b/src/quick/items/qquickwindowmanager_p.h
new file mode 100644
index 0000000000000000000000000000000000000000..8a5073effd394b4fb06b93017d5ff0746021fae5
--- /dev/null
+++ b/src/quick/items/qquickwindowmanager_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKWINDOWMANAGER_P_H
+#define QQUICKWINDOWMANAGER_P_H
+
+#include <QtGui/QImage>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickCanvas;
+class QSGContext;
+
+class QQuickWindowManager
+{
+public:
+    virtual void show(QQuickCanvas *canvas) = 0;
+    virtual void hide(QQuickCanvas *canvas) = 0;
+
+    virtual void canvasDestroyed(QQuickCanvas *canvas) = 0;
+
+    virtual void paint(QQuickCanvas *canvas) = 0;
+    virtual QImage grab(QQuickCanvas *canvas) = 0;
+    virtual void resize(QQuickCanvas *canvas, const QSize &size) = 0;
+
+    virtual void maybeUpdate(QQuickCanvas *canvas) = 0;
+
+    virtual bool *allowMainThreadProcessing() = 0;
+
+    virtual QSGContext *sceneGraphContext() const = 0;
+
+    // ### make this less of a singleton
+    static QQuickWindowManager *instance();
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKWINDOWMANAGER_P_H
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index 93fea15921d4811a43afc6a933664709eea9f9a5..b83e328158ddd3407e6750428fe337ff878e6ef9 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -39,30 +39,25 @@
 **
 ****************************************************************************/
 
-#include "qsgcontext_p.h"
-#include <QtQuick/private/qsgrenderer_p.h>
-#include <QtQuick/qsgnode.h>
-
-#include <QtQuick/private/qdeclarativepixmapcache_p.h>
-
-#include <private/qsgdefaultrenderer_p.h>
-
+#include <QtQuick/private/qsgcontext_p.h>
+#include <QtQuick/private/qsgdefaultrenderer_p.h>
 #include <QtQuick/private/qsgdistancefieldutil_p.h>
 #include <QtQuick/private/qsgdefaultdistancefieldglyphcache_p.h>
-#include <private/qsgdefaultrectanglenode_p.h>
-#include <private/qsgdefaultimagenode_p.h>
-#include <private/qsgdefaultglyphnode_p.h>
-#include <private/qsgdistancefieldglyphnode_p.h>
-
+#include <QtQuick/private/qsgdefaultrectanglenode_p.h>
+#include <QtQuick/private/qsgdefaultimagenode_p.h>
+#include <QtQuick/private/qsgdefaultglyphnode_p.h>
+#include <QtQuick/private/qsgdistancefieldglyphnode_p.h>
 #include <QtQuick/private/qsgtexture_p.h>
+#include <QtQuick/private/qdeclarativepixmapcache_p.h>
+
 #include <QGuiApplication>
 #include <QOpenGLContext>
 
 #include <QDeclarativeImageProvider>
+#include <private/qdeclarativeglobal_p.h>
 
 #include <private/qobject_p.h>
 #include <qmutex.h>
-#include <private/qdeclarativeglobal_p.h>
 
 DEFINE_BOOL_CONFIG_OPTION(qmlFlashMode, QML_FLASH_MODE)
 DEFINE_BOOL_CONFIG_OPTION(qmlTranslucentMode, QML_TRANSLUCENT_MODE)
@@ -140,14 +135,25 @@ QSGContext::QSGContext(QObject *parent) :
 
 
 QSGContext::~QSGContext()
+{
+    invalidate();
+}
+
+
+
+void QSGContext::invalidate()
 {
     Q_D(QSGContext);
     qDeleteAll(d->textures.values());
     d->textures.clear();
-    delete d->renderer;
-    delete d->rootNode;
     qDeleteAll(d->materials.values());
+    d->materials.clear();
     delete d->distanceFieldCacheManager;
+    d->distanceFieldCacheManager = 0;
+
+    d->gl = 0;
+
+    emit invalidated();
 }
 
 
@@ -181,28 +187,6 @@ void QSGContext::textureFactoryDestroyed(QObject *o)
 }
 
 
-
-/*!
-    Returns the renderer. The renderer instance is created through the adaptation layer.
- */
-QSGRenderer *QSGContext::renderer() const
-{
-    Q_D(const QSGContext);
-    return d->renderer;
-}
-
-
-/*!
-    Returns the root node. The root node instance is only created once the scene graph
-    context becomes ready.
- */
-QSGRootNode *QSGContext::rootNode() const
-{
-    Q_D(const QSGContext);
-    return d->rootNode;
-}
-
-
 QOpenGLContext *QSGContext::glContext() const
 {
     Q_D(const QSGContext);
@@ -218,16 +202,9 @@ void QSGContext::initialize(QOpenGLContext *context)
     Q_D(QSGContext);
 
     Q_ASSERT(!d->gl);
-
     d->gl = context;
 
-    d->renderer = createRenderer();
-    d->renderer->setClearColor(Qt::white);
-
-    d->rootNode = new QSGRootNode();
-    d->renderer->setRootNode(d->rootNode);
-
-    emit ready();
+    emit initialized();
 }
 
 
@@ -242,15 +219,15 @@ bool QSGContext::isReady() const
 }
 
 
-void QSGContext::renderNextFrame(QOpenGLFramebufferObject *fbo)
+void QSGContext::renderNextFrame(QSGRenderer *renderer, QOpenGLFramebufferObject *fbo)
 {
     Q_D(QSGContext);
 
     if (fbo) {
         QSGBindableFbo bindable(fbo);
-        d->renderer->renderScene(bindable);
+        renderer->renderScene(bindable);
     } else {
-        d->renderer->renderScene();
+        renderer->renderScene();
     }
 
 }
@@ -344,7 +321,7 @@ QSGRenderer *QSGContext::createRenderer()
 
 bool QSGContext::canDecodeImageToTexture() const
 {
-    return true;
+    return false;
 }
 
 
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index ded9d2727ae35ed88488dcd7f8f08590401fdf42..0d69a4fb471f91702435b46cc4397f244e5fc7e6 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -56,6 +56,8 @@ QT_BEGIN_HEADER
 
 QT_BEGIN_NAMESPACE
 
+QT_MODULE(Declarative)
+
 class QSGContextPrivate;
 class QSGRectangleNode;
 class QSGImageNode;
@@ -83,11 +85,7 @@ public:
     ~QSGContext();
 
     virtual void initialize(QOpenGLContext *context);
-
-    QSGRenderer *renderer() const;
-
-    void setRootNode(QSGRootNode *node);
-    QSGRootNode *rootNode() const;
+    virtual void invalidate();
 
     QOpenGLContext *glContext() const;
 
@@ -95,7 +93,7 @@ public:
 
     QSGMaterialShader *prepareMaterial(QSGMaterial *material);
 
-    virtual void renderNextFrame(QOpenGLFramebufferObject *fbo = 0);
+    virtual void renderNextFrame(QSGRenderer *renderer, QOpenGLFramebufferObject *fbo = 0);
 
     virtual QSGDistanceFieldGlyphCache *createDistanceFieldGlyphCache(const QRawFont &font);
 
@@ -106,8 +104,9 @@ public:
 
     virtual bool canDecodeImageToTexture() const;
     virtual QSGTexture *decodeImageToTexture(QIODevice *dev,
-                                                     QSize *size,
-                                                     const QSize &requestSize);
+                                             QSize *size,
+                                             const QSize &requestSize);
+
     virtual QSGTexture *createTexture(const QImage &image = QImage()) const;
     virtual QSize minimumFBOSize() const;
 
@@ -128,11 +127,13 @@ public:
 
     virtual QAnimationDriver *createAnimationDriver(QObject *parent);
 
-signals:
-    void ready();
 
 public slots:
     void textureFactoryDestroyed(QObject *o);
+
+signals:
+    void initialized();
+    void invalidated();
 };
 
 QT_END_NAMESPACE
diff --git a/tests/auto/qtquick2/qquickcanvas/data/AnimationsWhileHidden.qml b/tests/auto/qtquick2/qquickcanvas/data/AnimationsWhileHidden.qml
new file mode 100644
index 0000000000000000000000000000000000000000..e95b029210ec0ac9cc10594dcb3cb8e5b1376845
--- /dev/null
+++ b/tests/auto/qtquick2/qquickcanvas/data/AnimationsWhileHidden.qml
@@ -0,0 +1,17 @@
+import QtQuick 2.0
+import QtQuick.Window 2.0 as Window
+
+Window.Window
+{
+    id: win
+    visible: true
+    width: 250
+    height: 250
+
+    SequentialAnimation {
+        PauseAnimation { duration: 500 }
+        PropertyAction { target: win; property: "visible"; value: true }
+        loops: Animation.Infinite
+        running: true
+    }
+}
diff --git a/tests/auto/qtquick2/qquickcanvas/qquickcanvas.pro b/tests/auto/qtquick2/qquickcanvas/qquickcanvas.pro
index c95d474a2125e0553d2a878189ffc55534971753..b4a4bc5d9cf8d69b76a27cb458744d4c69c20484 100644
--- a/tests/auto/qtquick2/qquickcanvas/qquickcanvas.pro
+++ b/tests/auto/qtquick2/qquickcanvas/qquickcanvas.pro
@@ -6,3 +6,7 @@ macx:CONFIG -= app_bundle
 
 CONFIG += parallel_test
 QT += core-private gui-private declarative-private quick-private testlib
+
+OTHER_FILES += \
+    data/AnimationsWhileHidden.qml
+
diff --git a/tests/auto/qtquick2/qquickcanvas/tst_qquickcanvas.cpp b/tests/auto/qtquick2/qquickcanvas/tst_qquickcanvas.cpp
index f894ff3d39fa9ff3cac4cf16b65b01bcacd5d09a..60522b7d44c319f8a0ec5d7126ce1569bb436a3d 100644
--- a/tests/auto/qtquick2/qquickcanvas/tst_qquickcanvas.cpp
+++ b/tests/auto/qtquick2/qquickcanvas/tst_qquickcanvas.cpp
@@ -203,6 +203,11 @@ private slots:
 
     void qmlCreation();
     void clearColor();
+
+    void grab();
+    void multipleWindows();
+
+    void animationsWhileHidden();
 };
 
 tst_qquickcanvas::tst_qquickcanvas()
@@ -221,6 +226,7 @@ void tst_qquickcanvas::cleanupTestCase()
 void tst_qquickcanvas::constantUpdates()
 {
     QQuickCanvas canvas;
+    canvas.resize(250, 250);
     ConstantUpdateItem item(canvas.rootItem());
     canvas.show();
     QTRY_VERIFY(item.iterations > 60);
@@ -520,6 +526,8 @@ void tst_qquickcanvas::mouseFiltering()
     QCOMPARE(middleItem->mousePressId, 1);
     QCOMPARE(bottomItem->mousePressId, 2);
     QCOMPARE(topItem->mousePressId, 3);
+
+    delete canvas;
 }
 
 void tst_qquickcanvas::qmlCreation()
@@ -552,6 +560,68 @@ void tst_qquickcanvas::clearColor()
     delete canvas;
 }
 
+void tst_qquickcanvas::grab()
+{
+    QQuickCanvas canvas;
+    canvas.setClearColor(Qt::red);
+
+    canvas.resize(250, 250);
+    canvas.show();
+
+    QImage content = canvas.grabFrameBuffer();
+    QCOMPARE(content.width(), canvas.width());
+    QCOMPARE(content.height(), canvas.height());
+    QCOMPARE((uint) content.convertToFormat(QImage::Format_RGB32).pixel(0, 0), (uint) 0xffff0000);
+}
+
+void tst_qquickcanvas::multipleWindows()
+{
+    QList<QQuickCanvas *> windows;
+    for (int i=0; i<6; ++i) {
+        QQuickCanvas *c = new QQuickCanvas();
+        c->setClearColor(Qt::GlobalColor(Qt::red + i));
+        c->resize(300, 200);
+        c->setPos(100 + i * 30, 100 + i * 20);
+        c->show();
+        windows << c;
+        QVERIFY(c->visible());
+    }
+
+    // move them
+    for (int i=0; i<windows.size(); ++i) {
+        QQuickCanvas *c = windows.at(i);
+        c->setPos(c->x() - 10, c->y() - 10);
+    }
+
+    // resize them
+    for (int i=0; i<windows.size(); ++i) {
+        QQuickCanvas *c = windows.at(i);
+        c->resize(200, 150);
+    }
+
+    qDeleteAll(windows);
+}
+
+void tst_qquickcanvas::animationsWhileHidden()
+{
+    QDeclarativeEngine engine;
+    QDeclarativeComponent component(&engine);
+    component.loadUrl(TESTDATA("AnimationsWhileHidden.qml"));
+    QObject* created = component.create();
+
+    QQuickCanvas* canvas = qobject_cast<QQuickCanvas*>(created);
+    QVERIFY(canvas);
+    QVERIFY(canvas->visible());
+
+    // Now hide the window and verify that it went off screen
+    canvas->hide();
+    QTest::qWait(10);
+    QVERIFY(!canvas->visible());
+
+    // Running animaiton should cause it to become visible again shortly.
+    QTRY_VERIFY(canvas->visible());
+}
+
 QTEST_MAIN(tst_qquickcanvas)
 
 #include "tst_qquickcanvas.moc"
diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp
index 6cefc8a5de5ac490617ea09d8611a88bfa42b3f8..a9a03aac6c1f2ceb9226047c9d0505ca89fc8291 100644
--- a/tools/qmlscene/main.cpp
+++ b/tools/qmlscene/main.cpp
@@ -159,7 +159,6 @@ struct Options
     bool scenegraphOnGraphicsview;
     bool clip;
     bool versionDetection;
-    bool vsync;
 };
 
 #if defined(QMLSCENE_BUNDLE)
@@ -364,8 +363,6 @@ int main(int argc, char ** argv)
                 options.versionDetection = false;
             else if (lowerArgument == QLatin1String("-i") && i + 1 < argc)
                 imports.append(QString::fromLatin1(argv[++i]));
-            else if (lowerArgument == QLatin1String("--no-vsync-animations"))
-                options.vsync = false;
             else if (lowerArgument == QLatin1String("--help")
                      || lowerArgument == QLatin1String("-help")
                      || lowerArgument == QLatin1String("--h")
@@ -395,7 +392,6 @@ int main(int argc, char ** argv)
         if (options.versionDetection)
             checkAndAdaptVersion(options.file);
         QQuickView *qxView = new MyQQuickView();
-        qxView->setVSyncAnimations(options.vsync);
         engine = qxView->engine();
         for (int i = 0; i < imports.size(); ++i)
             engine->addImportPath(imports.at(i));