diff --git a/src/libkwineffects/kwinquickeffect.cpp b/src/libkwineffects/kwinquickeffect.cpp index aad187e13a..df7d1c8369 100644 --- a/src/libkwineffects/kwinquickeffect.cpp +++ b/src/libkwineffects/kwinquickeffect.cpp @@ -6,9 +6,11 @@ #include "kwinquickeffect.h" +#include "logging_p.h" #include "sharedqmlengine.h" #include +#include #include #include #include @@ -16,6 +18,24 @@ namespace KWin { +class QuickSceneViewIncubator : public QQmlIncubator +{ +public: + QuickSceneViewIncubator(const std::function &statusChangedCallback) + : QQmlIncubator(QQmlIncubator::Asynchronous) + , m_statusChangedCallback(statusChangedCallback) + { + } + + void statusChanged(QQmlIncubator::Status status) override + { + m_statusChangedCallback(this); + } + +private: + std::function m_statusChangedCallback; +}; + class QuickSceneEffectPrivate { public: @@ -28,6 +48,7 @@ public: SharedQmlEngine::Ptr qmlEngine; std::unique_ptr qmlComponent; QUrl source; + std::map> incubators; std::map> views; QPointer mouseImplicitGrab; bool running = false; @@ -336,29 +357,39 @@ void QuickSceneEffect::handleScreenAdded(EffectScreen *screen) void QuickSceneEffect::handleScreenRemoved(EffectScreen *screen) { d->views.erase(screen); + d->incubators.erase(screen); } void QuickSceneEffect::addScreen(EffectScreen *screen) { - QuickSceneView *view = new QuickSceneView(this, screen); auto properties = initialProperties(screen); - properties["width"] = view->geometry().width(); - properties["height"] = view->geometry().height(); - view->setRootItem(qobject_cast(d->qmlComponent->createWithInitialProperties(properties))); - // we need the focus always set to the view of activescreen at first, and changed only upon user interaction - if (view->contentItem()) { - view->contentItem()->setFocus(false); - } - view->setAutomaticRepaint(false); + properties["width"] = screen->geometry().width(); + properties["height"] = screen->geometry().height(); - connect(view, &QuickSceneView::repaintNeeded, this, [view]() { - effects->addRepaint(view->geometry()); + auto incubator = new QuickSceneViewIncubator([this, screen](QuickSceneViewIncubator *incubator) { + if (incubator->isReady()) { + auto view = new QuickSceneView(this, screen); + view->setRootItem(qobject_cast(incubator->object())); + if (view->contentItem()) { + view->contentItem()->setFocus(false); + } + view->setAutomaticRepaint(false); + connect(view, &QuickSceneView::repaintNeeded, this, [view]() { + effects->addRepaint(view->geometry()); + }); + connect(view, &QuickSceneView::renderRequested, view, &QuickSceneView::scheduleRepaint); + connect(view, &QuickSceneView::sceneChanged, view, &QuickSceneView::scheduleRepaint); + view->scheduleRepaint(); + d->views[screen].reset(view); + } else if (incubator->isError()) { + qCWarning(LIBKWINEFFECTS) << "Could not create a view for QML file" << d->qmlComponent->url(); + qCWarning(LIBKWINEFFECTS) << incubator->errors(); + } }); - connect(view, &QuickSceneView::renderRequested, view, &QuickSceneView::scheduleRepaint); - connect(view, &QuickSceneView::sceneChanged, view, &QuickSceneView::scheduleRepaint); - view->scheduleRepaint(); - d->views[screen].reset(view); + incubator->setInitialProperties(properties); + d->incubators[screen].reset(incubator); + d->qmlComponent->create(*incubator); } void QuickSceneEffect::startInternal() @@ -423,6 +454,7 @@ void QuickSceneEffect::stopInternal() disconnect(effects, &EffectsHandler::screenAdded, this, &QuickSceneEffect::handleScreenAdded); disconnect(effects, &EffectsHandler::screenRemoved, this, &QuickSceneEffect::handleScreenRemoved); + d->incubators.clear(); d->views.clear(); d->dummyWindow.reset(); d->running = false;