7#include <QtWidgets/private/qwidgetrepaintmanager_p.h>
9#include "private/qquickwindow_p.h"
10#include "private/qquickitem_p.h"
11#include "private/qquickitemchangelistener_p.h"
12#include "private/qquickrendercontrol_p.h"
13#include "private/qsgrhisupport_p.h"
15#include "private/qsgsoftwarerenderer_p.h"
17#include <private/qqmldebugconnector_p.h>
18#include <private/qquickprofiler_p.h>
19#include <private/qqmldebugserviceinterfaces_p.h>
21#include <QtQml/qqmlengine.h>
22#include <QtQml/qqmlcomponent.h>
23#include <private/qqmlengine_p.h>
24#include <QtCore/qbasictimer.h>
25#include <QtGui/QOffscreenSurface>
26#include <QtGui/private/qguiapplication_p.h>
27#include <QtGui/qpa/qplatformintegration.h>
29#include <QtGui/QPainter>
31#include <QtQuick/QSGRendererInterface>
34#if QT_CONFIG(messagebox)
35# include <QtWidgets/QMessageBox>
37# include <QtCore/QLibraryInfo>
38# include <QtCore/qt_windows.h>
41#include <QtQuick/qquickgraphicsdevice.h>
42#include <QtQuick/qquickrendertarget.h>
44#include "private/qwidget_p.h"
46#if QT_CONFIG(graphicsview)
47#include <QtWidgets/qgraphicsscene.h>
48#include <QtWidgets/qgraphicsview.h>
52#include <QtGui/private/qvulkandefaultinstance_p.h>
57QQuickWidgetOffscreenWindow::QQuickWidgetOffscreenWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control)
58:QQuickWindow(dd, control)
60 setTitle(QString::fromLatin1(
"Offscreen"));
61 setObjectName(QString::fromLatin1(
"QQuickWidgetOffscreenWindow"));
71 visibility = visible ? QWindow::Windowed : QWindow::Hidden;
72 q->visibilityChanged(visibility);
90 Q_DECLARE_PUBLIC(QQuickWidgetRenderControl)
98#if QT_CONFIG(graphicsview)
116 : QQuickRenderControl(*(
new QQuickWidgetRenderControlPrivate(
this, quickWidget)),
nullptr)
122 Q_D(QQuickWidgetRenderControl);
124 *offset = d->m_quickWidget->mapTo(d->m_quickWidget->window(), QPoint());
126 QWindow *result =
nullptr;
127#if QT_CONFIG(graphicsview)
128 QWidgetPrivate *widgetd = QWidgetPrivate::get(d->m_quickWidget);
129 if (widgetd->extra) {
130 if (
auto proxy = widgetd->extra->proxyWidget) {
131 auto scene = proxy->scene();
133 const auto views = scene->views();
134 if (!views.isEmpty()) {
137 auto candidateView = views.first();
138 result = candidateView->window()->windowHandle();
145 result = d->m_quickWidget->window()->windowHandle();
155 offscreenWindow->setScreen(q->screen());
158 QWidget::connect(offscreenWindow, SIGNAL(sceneGraphInitialized()), q, SLOT(createFramebufferObject()));
159 QWidget::connect(offscreenWindow, SIGNAL(sceneGraphInvalidated()), q, SLOT(destroyFramebufferObject()));
160 QWidget::connect(offscreenWindow, &QQuickWindow::focusObjectChanged, q, &QQuickWidget::propagateFocusObjectChanged);
162#if QT_CONFIG(accessibility)
163 QAccessible::installFactory(&qAccessibleQuickWidgetFactory);
176 renderControl =
new QQuickWidgetRenderControl(q);
177 if (!offscreenWindow) {
178 offscreenWindow =
new QQuickWidgetOffscreenWindow(*
new QQuickWidgetOffscreenWindowPrivate(), renderControl);
179 offscreenWindow->setProperty(
"_q_parentWidget", QVariant::fromValue(q));
183 auto sgRendererInterface = offscreenWindow->rendererInterface();
184 if (sgRendererInterface && sgRendererInterface->graphicsApi() == QSGRendererInterface::Software)
195 if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RhiBasedRendering))
196 setRenderToTexture();
198 qWarning(
"QQuickWidget is not supported on this platform.");
203 if (!engine.isNull() && !engine.data()->incubationController())
204 engine.data()->setIncubationController(offscreenWindow->incubationController());
206 q->setMouseTracking(
true);
207 q->setFocusPolicy(Qt::StrongFocus);
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224 q->setAttribute(Qt::WA_AcceptTouchEvents);
227#if QT_CONFIG(quick_draganddrop)
228 q->setAcceptDrops(
true);
231 QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
232 QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
237 Q_Q(
const QQuickWidget);
238 if (!engine.isNull())
241 engine =
new QQmlEngine(
const_cast<QQuickWidget*>(q));
242 engine.data()->setIncubationController(offscreenWindow->incubationController());
249 rhi->makeThreadLocalNativeContextCurrent();
259 if (offscreenWindow->isPersistentSceneGraph()
260 && qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)
261 && rhiConfig().api() == QPlatformBackingStoreRhiConfig::OpenGL)
272 QScopedPointer<QQuickWindow> oldOffScreenWindow(offscreenWindow);
273 offscreenWindow =
nullptr;
276 renderControl =
new QQuickWidgetRenderControl(q);
279 if (oldOffScreenWindow)
280 offscreenWindow->setColor(oldOffScreenWindow->color());
282 QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
283 QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
285 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(root))
286 sgItem->setParentItem(offscreenWindow->contentItem());
292 , offscreenWindow(
nullptr)
300 , resizeMode(QQuickWidget::SizeViewToRootObject)
330 q->destroyFramebufferObject();
331 delete offscreenWindow;
333 offscreenRenderer.reset();
341 if (!source.isEmpty()) {
342 component =
new QQmlComponent(engine.data(), source, q);
344 q->continueExecute();
346 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
347 q, SLOT(continueExecute()));
357 component =
new QQmlComponent(engine.data(), uri, typeName, q);
359 q->continueExecute();
361 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
362 q, SLOT(continueExecute()));
367 const QRectF &oldGeometry)
370 if (resizeItem == root && resizeMode == QQuickWidget::SizeViewToRootObject) {
372 resizetimer.start(0,q);
374 QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, oldGeometry);
384 q->createFramebufferObject();
388 qWarning(
"QQuickWidget: Attempted to render scene with no rhi");
398 QQuickRenderControlPrivate::FrameStatus frameStatus = QQuickRenderControlPrivate::get(renderControl)->frameStatus;
399 if (frameStatus == QQuickRenderControlPrivate::DeviceLostInBeginFrame) {
406 if (frameStatus != QQuickRenderControlPrivate::RecordingFrame) {
407 qWarning(
"QQuickWidget: Failed to begin recording a frame");
425 if (!offscreenWindow)
427 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(offscreenWindow);
428 auto softwareRenderer =
static_cast<QSGSoftwareRenderer*>(cd->renderer);
429 if (softwareRenderer && !softwareImage.isNull()) {
430 softwareRenderer->setCurrentPaintDevice(&softwareImage);
432 softwareRenderer->markDirty();
437 updateRegion += softwareRenderer->flushRegion();
447 if (!q->isVisible() || fakeHidden)
452#if QT_CONFIG(graphicsview)
453 if (q->window()->graphicsProxyWidget())
454 QWidgetPrivate::nearestGraphicsProxyWidget(q)->update();
458 if (!useSoftwareRenderer)
460 else if (!updateRegion.isEmpty())
461 q->update(updateRegion);
476 QRhiCommandBuffer *cb =
nullptr;
477 rhi->beginOffscreenFrame(&cb);
478 QRhiResourceUpdateBatch *resUpd =
rhi->nextResourceUpdateBatch();
479 QRhiReadbackResult readResult;
480 resUpd->readBackTexture(QRhiReadbackDescription(
outputTexture), &readResult);
481 cb->resourceUpdate(resUpd);
482 rhi->endOffscreenFrame();
483 if (!readResult.data.isEmpty()) {
484 QImage wrapperImage(
reinterpret_cast<
const uchar *>(readResult.data.constData()),
485 readResult.pixelSize.width(), readResult.pixelSize.height(),
486 QImage::Format_RGBA8888_Premultiplied);
487 if (
rhi->isYUpInFramebuffer())
488 return wrapperImage.flipped();
490 return wrapperImage.copy();
495 return offscreenWindow->grabWindow();
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
644
645
646
649
650
651
652
653QQuickWidget::QQuickWidget(QWidget *parent)
654 : QWidget(*(
new QQuickWidgetPrivate), parent, {})
660
661
662
663
664
665QQuickWidget::QQuickWidget(
const QUrl &source, QWidget *parent)
666 : QQuickWidget(parent)
672
673
674
675
676
677
678QQuickWidget::QQuickWidget(QAnyStringView uri, QAnyStringView typeName, QWidget *parent)
679 : QQuickWidget(parent)
681 loadFromModule(uri, typeName);
685
686
687
688
689
690
691QQuickWidget::QQuickWidget(QQmlEngine* engine, QWidget *parent)
692 : QWidget(*(
new QQuickWidgetPrivate), parent, {})
694 d_func()->init(engine);
698
699
700QQuickWidget::~QQuickWidget()
709 d->rhi->removeCleanupCallback(
this);
720
721
722
723
724
725
726
727
728
731
732
733
734
735
736
737
738
739void QQuickWidget::setSource(
const QUrl& url)
747
748
749
750
751void QQuickWidget::setContent(
const QUrl& url, QQmlComponent *component, QObject* item)
755 d->component = component;
757 if (d->component && d->component->isError()) {
758 const QList<QQmlError> errorList = d->component->errors();
759 for (
const QQmlError &error : errorList) {
760 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
763 emit statusChanged(status());
767 d->setRootObject(item);
768 emit statusChanged(status());
771
772
773
774
775
776
777
778
779
780
781void QQuickWidget::setInitialProperties(
const QVariantMap &initialProperties)
784 d->initialProperties = initialProperties;
788
789
790
791
792
793
794
795
796
797
798
799
800void QQuickWidget::loadFromModule(QAnyStringView uri, QAnyStringView typeName)
804 d->execute(uri, typeName);
808
809
810
811
812QUrl QQuickWidget::source()
const
814 Q_D(
const QQuickWidget);
819
820
821
822QQmlEngine* QQuickWidget::engine()
const
824 Q_D(
const QQuickWidget);
826 return const_cast<QQmlEngine *>(d->engine.data());
830
831
832
833
834
835
836QQmlContext* QQuickWidget::rootContext()
const
838 Q_D(
const QQuickWidget);
840 return d->engine.data()->rootContext();
844
845
846
847
848
849
850
851
852
855
856
857
858
859
860
863
864
865
866
867
868
869
870
871
872
873
874
875
878
879
880
882QQuickWidget::Status QQuickWidget::status()
const
884 Q_D(
const QQuickWidget);
885 if (!d->engine && !d->source.isEmpty())
886 return QQuickWidget::Error;
889 return QQuickWidget::Null;
891 if (d->component->status() == QQmlComponent::Ready && !d->root)
892 return QQuickWidget::Error;
894 return QQuickWidget::Status(d->component->status());
898
899
900
901
902
903QList<QQmlError> QQuickWidget::errors()
const
905 Q_D(
const QQuickWidget);
906 QList<QQmlError> errs;
909 errs = d->component->errors();
911 if (!d->engine && !d->source.isEmpty()) {
913 error.setDescription(QLatin1String(
"QQuickWidget: invalid qml engine."));
916 if (d->component && d->component->status() == QQmlComponent::Ready && !d->root) {
918 error.setDescription(QLatin1String(
"QQuickWidget: invalid root object."));
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
942void QQuickWidget::setResizeMode(ResizeMode mode)
945 if (d->resizeMode == mode)
949 if (d->resizeMode == SizeViewToRootObject) {
950 QQuickItemPrivate *p = QQuickItemPrivate::get(d->root);
951 p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
955 d->resizeMode = mode;
964 if (resizeMode == QQuickWidget::SizeViewToRootObject) {
965 QQuickItemPrivate *p = QQuickItemPrivate::get(root);
966 p->addItemChangeListener(
this, QQuickItemPrivate::Geometry);
978 if (resizeMode == QQuickWidget::SizeViewToRootObject) {
979 QSize newSize = QSize(root->width(), root->height());
980 if (newSize.isValid()) {
981 if (newSize != q->size()) {
984 }
else if (offscreenWindow->size().isEmpty()) {
987 offscreenWindow->resize(newSize);
988 offscreenWindow->contentItem()->setSize(newSize);
991 }
else if (resizeMode == QQuickWidget::SizeRootObjectToView) {
992 const bool needToUpdateWidth = !qFuzzyCompare(q->width(), root->width());
993 const bool needToUpdateHeight = !qFuzzyCompare(q->height(), root->height());
995 if (needToUpdateWidth && needToUpdateHeight) {
1000 const QSizeF newSize(q->width(), q->height());
1001 offscreenWindow->resize(newSize.toSize());
1002 offscreenWindow->contentItem()->setSize(newSize);
1003 root->setSize(newSize);
1004 }
else if (needToUpdateWidth) {
1005 const int newWidth = q->width();
1006 offscreenWindow->setWidth(newWidth);
1007 offscreenWindow->contentItem()->setWidth(newWidth);
1008 root->setWidth(newWidth);
1009 }
else if (needToUpdateHeight) {
1010 const int newHeight = q->height();
1011 offscreenWindow->setHeight(newHeight);
1012 offscreenWindow->contentItem()->setHeight(newHeight);
1013 root->setHeight(newHeight);
1019
1020
1021
1022
1026 if (offscreenWindow ==
nullptr)
1029 const QPoint &pos = q->mapToGlobal(QPoint(0, 0));
1030 if (offscreenWindow->position() != pos)
1031 offscreenWindow->setPosition(pos);
1036 QSize rootObjectSize(0,0);
1037 int widthCandidate = -1;
1038 int heightCandidate = -1;
1040 widthCandidate = root->width();
1041 heightCandidate = root->height();
1043 if (widthCandidate > 0) {
1044 rootObjectSize.setWidth(widthCandidate);
1046 if (heightCandidate > 0) {
1047 rootObjectSize.setHeight(heightCandidate);
1049 return rootObjectSize;
1056 QString translatedMessage;
1057 QString untranslatedMessage;
1058 QQuickWindowPrivate::rhiCreationFailureMessage(QLatin1String(
"QRhi"), &translatedMessage, &untranslatedMessage);
1060 static const QMetaMethod errorSignal = QMetaMethod::fromSignal(&QQuickWidget::sceneGraphError);
1061 const bool signalConnected = q->isSignalConnected(errorSignal);
1062 if (signalConnected)
1063 emit q->sceneGraphError(QQuickWindow::ContextNotAvailable, translatedMessage);
1065#if defined(Q_OS_WIN) && QT_CONFIG(messagebox)
1066 if (!signalConnected && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow())
1067 QMessageBox::critical(q, QCoreApplication::applicationName(), translatedMessage);
1069 if (!signalConnected)
1070 qFatal(
"%s", qPrintable(untranslatedMessage));
1076 case QSGRendererInterface::OpenGL:
1077 return QPlatformBackingStoreRhiConfig::OpenGL;
1078 case QSGRendererInterface::Vulkan:
1079 return QPlatformBackingStoreRhiConfig::Vulkan;
1080 case QSGRendererInterface::Direct3D11:
1081 return QPlatformBackingStoreRhiConfig::D3D11;
1082 case QSGRendererInterface::Direct3D12:
1083 return QPlatformBackingStoreRhiConfig::D3D12;
1084 case QSGRendererInterface::Metal:
1085 return QPlatformBackingStoreRhiConfig::Metal;
1087 return QPlatformBackingStoreRhiConfig::Null;
1098 QRhi *backingStoreRhi = QWidgetPrivate::rhi();
1099 if (backingStoreRhi &&
rhi != backingStoreRhi)
1105 const bool onlyNeedsSgInit = rhi && !offscreenWindow->isSceneGraphInitialized();
1107 if (!onlyNeedsSgInit) {
1111 if (QRhi *backingStoreRhi = QWidgetPrivate::rhi()) {
1112 rhi = backingStoreRhi;
1114 rhi->addCleanupCallback(q, [
this](QRhi *rhi) {
1115 if (
this->rhi == rhi) {
1118 this->rhi =
nullptr;
1129 offscreenRenderer.setConfig(rhiConfig());
1130 offscreenRenderer.setFormat(q->format());
1132 if (offscreenRenderer.create())
1133 rhi = offscreenRenderer.rhi();
1138 if (rhi && rhi->backend() != QBackingStoreRhiSupport::apiToRhiBackend(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()))) {
1139 qWarning(
"The top-level window is not using the expected graphics API for composition, "
1140 "'%s' is not compatible with this QQuickWidget",
1141 rhi->backendName());
1147 if (!offscreenWindow->isSceneGraphInitialized()) {
1148 offscreenWindow->setGraphicsDevice(QQuickGraphicsDevice::fromRhi(rhi));
1149#if QT_CONFIG(vulkan)
1150 if (QWindow *w = q->window()->windowHandle())
1151 offscreenWindow->setVulkanInstance(w->vulkanInstance());
1152 else if (rhi == offscreenRenderer.rhi())
1153 offscreenWindow->setVulkanInstance(QVulkanDefaultInstance::instance());
1158 qWarning(
"QQuickWidget: Failed to get a QRhi from the top-level widget's window");
1162void QQuickWidget::createFramebufferObject()
1168 if (size().isEmpty())
1174 const QPoint &globalPos = mapToGlobal(QPoint(0, 0));
1175 d->offscreenWindow->setGeometry(globalPos.x(), globalPos.y(), width(), height());
1176 d->offscreenWindow->contentItem()->setSize(QSizeF(width(), height()));
1178 if (d->useSoftwareRenderer) {
1179 const QSize imageSize = size() * devicePixelRatio();
1180 d->softwareImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
1181 d->softwareImage.setDevicePixelRatio(devicePixelRatio());
1182 d->forceFullUpdate =
true;
1187 qWarning(
"QQuickWidget: Attempted to create output texture with no QRhi");
1191 int samples = d->requestedSamples;
1192 if (d->rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer))
1193 samples = QSGRhiSupport::chooseSampleCount(samples, d->rhi);
1197 const int minTexSize = d->rhi->resourceLimit(QRhi::TextureSizeMin);
1198 const int maxTexSize = d->rhi->resourceLimit(QRhi::TextureSizeMax);
1200 QSize fboSize = size() * devicePixelRatio();
1201 if (fboSize.width() > maxTexSize || fboSize.height() > maxTexSize) {
1202 qWarning(
"QQuickWidget: Requested backing texture size is %dx%d, but the maximum texture size for the 3D API implementation is %dx%d",
1203 fboSize.width(), fboSize.height(),
1204 maxTexSize, maxTexSize);
1206 fboSize.setWidth(qMin(maxTexSize, qMax(minTexSize, fboSize.width())));
1207 fboSize.setHeight(qMin(maxTexSize, qMax(minTexSize, fboSize.height())));
1210 if (!d->outputTexture) {
1211 d->outputTexture = d->rhi->newTexture(QRhiTexture::RGBA8, fboSize, 1, QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
1212 if (!d->outputTexture->create()) {
1213 qWarning(
"QQuickWidget: failed to create output texture of size %dx%d",
1214 fboSize.width(), fboSize.height());
1217 if (!d->depthStencil) {
1218 d->depthStencil = d->rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, fboSize, samples);
1219 if (!d->depthStencil->create()) {
1220 qWarning(
"QQuickWidget: failed to create depth/stencil buffer of size %dx%d and sample count %d",
1221 fboSize.width(), fboSize.height(), samples);
1224 if (samples > 1 && !d->msaaBuffer) {
1225 d->msaaBuffer = d->rhi->newRenderBuffer(QRhiRenderBuffer::Color, fboSize, samples);
1226 if (!d->msaaBuffer->create()) {
1227 qWarning(
"QQuickWidget: failed to create multisample renderbuffer of size %dx%d and sample count %d",
1228 fboSize.width(), fboSize.height(), samples);
1232 QRhiTextureRenderTargetDescription rtDesc;
1233 QRhiColorAttachment colorAtt;
1235 colorAtt.setTexture(d->outputTexture);
1237 colorAtt.setRenderBuffer(d->msaaBuffer);
1238 colorAtt.setResolveTexture(d->outputTexture);
1240 rtDesc.setColorAttachments({ colorAtt });
1241 rtDesc.setDepthStencilBuffer(d->depthStencil);
1242 d->rt = d->rhi->newTextureRenderTarget(rtDesc);
1243 d->rtRp = d->rt->newCompatibleRenderPassDescriptor();
1244 d->rt->setRenderPassDescriptor(d->rtRp);
1247 if (d->outputTexture->pixelSize() != fboSize) {
1248 d->outputTexture->setPixelSize(fboSize);
1249 if (!d->outputTexture->create()) {
1250 qWarning(
"QQuickWidget: failed to create resized output texture of size %dx%d",
1251 fboSize.width(), fboSize.height());
1253 d->depthStencil->setPixelSize(fboSize);
1254 if (!d->depthStencil->create()) {
1255 qWarning(
"QQuickWidget: failed to create resized depth/stencil buffer of size %dx%d",
1256 fboSize.width(), fboSize.height());
1258 if (d->msaaBuffer) {
1259 d->msaaBuffer->setPixelSize(fboSize);
1260 if (!d->msaaBuffer->create()) {
1261 qWarning(
"QQuickWidget: failed to create resized multisample renderbuffer of size %dx%d",
1262 fboSize.width(), fboSize.height());
1267 d->offscreenWindow->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(d->rt));
1269 d->renderControl->setSamples(samples);
1274 Q_ASSERT(!d->offscreenWindow->handle());
1277void QQuickWidget::destroyFramebufferObject()
1281 if (d->useSoftwareRenderer) {
1282 d->softwareImage = QImage();
1290 delete d->depthStencil;
1291 d->depthStencil =
nullptr;
1292 delete d->msaaBuffer;
1293 d->msaaBuffer =
nullptr;
1294 delete d->outputTexture;
1295 d->outputTexture =
nullptr;
1298QQuickWidget::ResizeMode QQuickWidget::resizeMode()
const
1300 Q_D(
const QQuickWidget);
1301 return d->resizeMode;
1305
1306
1307void QQuickWidget::continueExecute()
1310 disconnect(d->component, SIGNAL(statusChanged(QQmlComponent::Status)),
this, SLOT(continueExecute()));
1312 if (d->component->isError()) {
1313 const QList<QQmlError> errorList = d->component->errors();
1314 for (
const QQmlError &error : errorList) {
1315 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
1318 emit statusChanged(status());
1322 std::unique_ptr<QObject> obj(d->initialProperties.empty()
1323 ? d->component->create()
1324 : d->component->createWithInitialProperties(d->initialProperties));
1326 if (d->component->isError()) {
1327 const QList<QQmlError> errorList = d->component->errors();
1328 for (
const QQmlError &error : errorList) {
1329 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
1332 emit statusChanged(status());
1338 if (d->source.isEmpty())
1339 d->source = d->component->url();
1341 d->setRootObject(obj.get());
1343 Q_UNUSED(obj.release());
1344 emit statusChanged(status());
1348
1349
1356 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
1358 sgItem->setParentItem(offscreenWindow->contentItem());
1359 }
else if (qobject_cast<QWindow *>(obj)) {
1360 qWarning() <<
"QQuickWidget does not support using windows as a root item." << Qt::endl
1362 <<
"If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << Qt::endl;
1364 qWarning() <<
"QQuickWidget only supports loading of root objects that derive from QQuickItem." << Qt::endl
1366 <<
"Ensure your QML code is written for QtQuick 2, and uses a root that is or" << Qt::endl
1367 <<
"inherits from QtQuick's Item (not a Timer, QtObject, etc)." << Qt::endl;
1372 initialSize = rootObjectSize();
1373 bool resized = q->testAttribute(Qt::WA_Resized);
1374 if ((resizeMode == QQuickWidget::SizeViewToRootObject || !resized) &&
1375 initialSize != q->size()) {
1376 q->resize(initialSize);
1391 QPlatformBackingStoreRhiConfig config(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()));
1393 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(offscreenWindow);
1400 const bool debugLayerRequested = wd->graphicsConfig.isDebugLayerEnabled();
1401 config.setDebugLayer(debugLayerRequested);
1412 QPlatformTextureList::Flags flags = QWidgetPrivate::textureListFlags();
1413 flags |= QPlatformTextureList::NeedsPremultipliedAlphaBlending;
1418
1419
1420
1421void QQuickWidget::timerEvent(QTimerEvent* e)
1424 if (!e || e->timerId() == d->resizetimer.timerId()) {
1426 d->resizetimer.stop();
1427 }
else if (e->timerId() == d->updateTimer.timerId()) {
1428 d->eventPending =
false;
1429 d->updateTimer.stop();
1430 if (d->updatePending)
1431 d->renderSceneGraph();
1436
1437
1438
1439QSize QQuickWidget::sizeHint()
const
1441 Q_D(
const QQuickWidget);
1442 QSize rootObjectSize = d->rootObjectSize();
1443 if (rootObjectSize.isEmpty()) {
1446 return rootObjectSize;
1451
1452
1453
1454
1455
1456
1457QSize QQuickWidget::initialSize()
const
1459 Q_D(
const QQuickWidget);
1460 return d->initialSize;
1464
1465
1466
1467
1468
1469QQuickItem *QQuickWidget::rootObject()
const
1471 Q_D(
const QQuickWidget);
1476
1477
1478
1479
1480void QQuickWidget::resizeEvent(QResizeEvent *e)
1483 if (d->resizeMode == SizeRootObjectToView)
1486 if (e->size().isEmpty()) {
1488 d->fakeHidden =
true;
1492 bool needsSync =
false;
1493 if (d->fakeHidden) {
1495 d->fakeHidden =
false;
1500 if (d->useSoftwareRenderer) {
1502 if (d->softwareImage.size() != size() * devicePixelRatio()) {
1503 createFramebufferObject();
1509 if (!d->outputTexture && !d->offscreenWindow->isSceneGraphInitialized())
1511 if (!d->outputTexture || d->outputTexture->pixelSize() != size() * devicePixelRatio()) {
1513 createFramebufferObject();
1519 d->initializeWithRhi();
1523 qWarning(
"QQuickWidget::resizeEvent() no QRhi");
1528 d->render(needsSync);
1532bool QQuickWidget::focusNextPrevChild(
bool next)
1536 const auto *da = QQuickWindowPrivate::get(d->offscreenWindow)->deliveryAgentPrivate();
1539 auto *currentTarget = da->focusTargetItem();
1540 Q_ASSERT(currentTarget);
1542 auto *nextTarget = QQuickItemPrivate::nextPrevItemInTabFocusChain(currentTarget, next,
false);
1545 return QWidget::focusNextPrevChild(next);
1548 const Qt::Key k = next ? Qt::Key_Tab : Qt::Key_Backtab;
1549 QKeyEvent event(QEvent::KeyPress, k, Qt::NoModifier);
1550 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, k, Qt::NoModifier);
1551 QCoreApplication::sendEvent(d->offscreenWindow, &event);
1553 QKeyEvent releaseEvent(QEvent::KeyRelease, k, Qt::NoModifier);
1554 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, k, Qt::NoModifier);
1555 QCoreApplication::sendEvent(d->offscreenWindow, &releaseEvent);
1557 return event.isAccepted();
1561void QQuickWidget::keyPressEvent(QKeyEvent *e)
1564 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, e->key(),
1567 QCoreApplication::sendEvent(d->offscreenWindow, e);
1571void QQuickWidget::keyReleaseEvent(QKeyEvent *e)
1574 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, e->key(),
1577 QCoreApplication::sendEvent(d->offscreenWindow, e);
1581void QQuickWidget::mouseMoveEvent(QMouseEvent *e)
1584 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove, e->position().x(),
1591 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1592 e->button(), e->buttons(), e->modifiers(), e->source());
1594 mappedEvent.setTimestamp(e->timestamp());
1595 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1596 e->setAccepted(mappedEvent.isAccepted());
1600void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
1603 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
1604 e->button(), e->buttons());
1608 QMouseEvent pressEvent(QEvent::MouseButtonPress, e->position(), e->position(), e->globalPosition(),
1609 e->button(), e->buttons(), e->modifiers(), e->source());
1610 pressEvent.setTimestamp(e->timestamp());
1611 QCoreApplication::sendEvent(d->offscreenWindow, &pressEvent);
1612 e->setAccepted(pressEvent.isAccepted());
1613 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1614 e->button(), e->buttons(), e->modifiers(), e->source());
1615 mappedEvent.setTimestamp(e->timestamp());
1616 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1620void QQuickWidget::showEvent(QShowEvent *)
1623 bool shouldTriggerUpdate =
true;
1625 if (!d->useSoftwareRenderer) {
1626 d->initializeWithRhi();
1628 if (d->offscreenWindow->isSceneGraphInitialized()) {
1629 shouldTriggerUpdate =
false;
1638 if (!d->eventPending && d->updatePending) {
1639 d->updatePending =
false;
1645 if (shouldTriggerUpdate)
1649 d->offscreenWindow->setVisible(
true);
1650 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1651 service->setParentWindow(d->offscreenWindow, window()->windowHandle());
1655void QQuickWidget::hideEvent(QHideEvent *)
1658 if (!d->offscreenWindow->isPersistentSceneGraph())
1659 d->invalidateRenderControl();
1661 d->offscreenWindow->setVisible(
false);
1662 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1663 service->setParentWindow(d->offscreenWindow, d->offscreenWindow);
1667void QQuickWidget::mousePressEvent(QMouseEvent *e)
1670 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, e->button(),
1673 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1674 e->button(), e->buttons(), e->modifiers(), e->source());
1675 mappedEvent.setTimestamp(e->timestamp());
1676 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1677 e->setAccepted(mappedEvent.isAccepted());
1681void QQuickWidget::mouseReleaseEvent(QMouseEvent *e)
1684 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, e->button(),
1687 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1688 e->button(), e->buttons(), e->modifiers(), e->source());
1689 mappedEvent.setTimestamp(e->timestamp());
1690 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1691 e->setAccepted(mappedEvent.isAccepted());
1694#if QT_CONFIG(wheelevent)
1696void QQuickWidget::wheelEvent(QWheelEvent *e)
1699 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel,
1700 e->angleDelta().x(), e->angleDelta().y());
1703 QCoreApplication::sendEvent(d->offscreenWindow, e);
1708
1709
1710void QQuickWidget::focusInEvent(QFocusEvent * event)
1714 using FocusTarget = QWindowPrivate::FocusTarget;
1715 const Qt::FocusReason reason = event->reason();
1721 case Qt::TabFocusReason:
1722 case Qt::BacktabFocusReason: {
1723 const bool forward = reason == Qt::FocusReason::TabFocusReason;
1724 const FocusTarget target = forward ? FocusTarget::First : FocusTarget::Last;
1725 QQuickWindowPrivate::get(d->offscreenWindow)->setFocusToTarget(target, reason);
1731 d->offscreenWindow->focusInEvent(event);
1735
1736
1737void QQuickWidget::focusOutEvent(QFocusEvent * event)
1740 d->offscreenWindow->focusOutEvent(event);
1746 if (states & Qt::WindowMinimized)
1747 return Qt::WindowMinimized;
1748 if (states & Qt::WindowMaximized)
1749 return Qt::WindowMaximized;
1750 if (states & Qt::WindowFullScreen)
1751 return Qt::WindowFullScreen;
1754 return Qt::WindowNoState;
1759 auto item = qobject_cast<QQuickItem *>(object);
1764 for (
auto query : {Qt::ImCursorRectangle, Qt::ImAnchorRectangle, Qt::ImInputItemClipRectangle}) {
1765 if (e->queries() & query) {
1766 auto value = e->value(query);
1767 if (value.canConvert<QRectF>())
1768 e->setValue(query, item->mapRectToScene(value.toRectF()));
1772 if (e->queries() & Qt::ImCursorPosition) {
1773 auto value = e->value(Qt::ImCursorPosition);
1774 if (value.canConvert<QPointF>())
1775 e->setValue(Qt::ImCursorPosition, item->mapToScene(value.toPointF()));
1780bool QQuickWidget::event(QEvent *e)
1784 switch (e->type()) {
1787 case QEvent::TouchBegin:
1788 case QEvent::TouchEnd:
1789 case QEvent::TouchUpdate:
1790 case QEvent::TouchCancel: {
1792 bool res = QCoreApplication::sendEvent(d->offscreenWindow, e);
1793 if (e->isAccepted() && e->type() == QEvent::TouchBegin) {
1798 QPointerEvent *pointerEvent =
static_cast<QPointerEvent *>(e);
1799 auto deliveredPoints = pointerEvent->points();
1800 for (
auto &point : deliveredPoints) {
1801 if (pointerEvent->exclusiveGrabber(point) || !pointerEvent->passiveGrabbers(point).isEmpty())
1802 point.setAccepted(
true);
1808 case QEvent::FocusAboutToChange:
1809 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1811 case QEvent::InputMethod:
1812 return QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1813 case QEvent::InputMethodQuery:
1815 bool eventResult = QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1820 remapInputMethodQueryEvent(d->offscreenWindow->focusObject(),
static_cast<QInputMethodQueryEvent *>(e));
1824 case QEvent::WindowAboutToChangeInternal:
1826 d->rhi->removeCleanupCallback(
this);
1827 d->invalidateRenderControl();
1828 d->deviceLost =
true;
1832 case QEvent::WindowChangeInternal:
1833 d->handleWindowChange();
1836 case QEvent::ScreenChangeInternal:
1838 QScreen *newScreen = screen();
1839 if (d->offscreenWindow)
1840 d->offscreenWindow->setScreen(newScreen);
1843 case QEvent::DevicePixelRatioChange:
1844 if (d->useSoftwareRenderer || d->outputTexture) {
1847 createFramebufferObject();
1850 if (d->offscreenWindow) {
1851 QEvent dprChangeEvent(QEvent::DevicePixelRatioChange);
1852 QGuiApplication::sendEvent(d->offscreenWindow, &dprChangeEvent);
1857 d->updatePosition();
1860 case QEvent::WindowStateChange:
1861 d->offscreenWindow->setWindowState(resolveWindowState(windowState()));
1864 case QEvent::ShortcutOverride:
1865 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1867 case QEvent::Enter: {
1868 QEnterEvent *enterEvent =
static_cast<QEnterEvent *>(e);
1869 QEnterEvent mappedEvent(enterEvent->position(), enterEvent->scenePosition(),
1870 enterEvent->globalPosition());
1871 const bool ret = QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1872 e->setAccepted(mappedEvent.isAccepted());
1879 return QWidget::event(e);
1882#if QT_CONFIG(quick_draganddrop)
1885void QQuickWidget::dragEnterEvent(QDragEnterEvent *e)
1890 d->offscreenWindow->event(e);
1895void QQuickWidget::dragMoveEvent(QDragMoveEvent *e)
1900 d->offscreenWindow->event(e);
1904void QQuickWidget::dragLeaveEvent(QDragLeaveEvent *e)
1907 d->offscreenWindow->event(e);
1911void QQuickWidget::dropEvent(QDropEvent *e)
1914 d->offscreenWindow->event(e);
1922void QQuickWidget::triggerUpdate()
1925 d->updatePending =
true;
1926 if (!d->eventPending) {
1935 const int exhaustDelay = 5;
1936 d->updateTimer.start(exhaustDelay, Qt::PreciseTimer,
this);
1937 d->eventPending =
true;
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952void QQuickWidget::setFormat(
const QSurfaceFormat &format)
1955 QSurfaceFormat currentFormat = d->offscreenWindow->format();
1956 QSurfaceFormat newFormat = format;
1957 newFormat.setDepthBufferSize(qMax(newFormat.depthBufferSize(), currentFormat.depthBufferSize()));
1958 newFormat.setStencilBufferSize(qMax(newFormat.stencilBufferSize(), currentFormat.stencilBufferSize()));
1959 newFormat.setAlphaBufferSize(qMax(newFormat.alphaBufferSize(), currentFormat.alphaBufferSize()));
1965 d->requestedSamples = newFormat.samples();
1966 newFormat.setSamples(0);
1968 d->offscreenWindow->setFormat(newFormat);
1972
1973
1974
1975
1976
1977
1978QSurfaceFormat QQuickWidget::format()
const
1980 Q_D(
const QQuickWidget);
1981 return d->offscreenWindow->format();
1985
1986
1987
1988
1989QImage QQuickWidget::grabFramebuffer()
const
1991 return const_cast<QQuickWidgetPrivate *>(d_func())->grabFramebuffer();
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004void QQuickWidget::setClearColor(
const QColor &color)
2007 d->offscreenWindow->setColor(color);
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028QQuickWindow *QQuickWidget::quickWindow()
const
2030 Q_D(
const QQuickWidget);
2031 return d->offscreenWindow;
2035
2036
2037void QQuickWidget::paintEvent(QPaintEvent *event)
2040 if (d->useSoftwareRenderer) {
2041 QPainter painter(
this);
2042 d->updateRegion = d->updateRegion.united(event->region());
2043 if (d->updateRegion.isNull()) {
2045 painter.drawImage(rect(), d->softwareImage);
2047 QTransform transform;
2048 transform.scale(devicePixelRatio(), devicePixelRatio());
2050 QRegion targetRegion;
2051 d->updateRegion.swap(targetRegion);
2052 for (
auto targetRect : targetRegion) {
2053 auto sourceRect = transform.mapRect(QRectF(targetRect));
2054 painter.drawImage(targetRect, d->softwareImage, sourceRect);
2060void QQuickWidget::propagateFocusObjectChanged(QObject *focusObject)
2063 if (QApplication::focusObject() !=
this)
2065 if (QWindow *window = d->windowHandle(QWidgetPrivate::WindowHandleMode::TopLevel))
2066 emit window->focusObjectChanged(focusObject);
2071#include "moc_qquickwidget_p.cpp"
2073#include "moc_qquickwidget.cpp"