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.release());
1342 emit statusChanged(status());
1346
1347
1354 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
1356 sgItem->setParentItem(offscreenWindow->contentItem());
1357 }
else if (qobject_cast<QWindow *>(obj)) {
1358 qWarning() <<
"QQuickWidget does not support using windows as a root item." << Qt::endl
1360 <<
"If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << Qt::endl;
1362 qWarning() <<
"QQuickWidget only supports loading of root objects that derive from QQuickItem." << Qt::endl
1364 <<
"Ensure your QML code is written for QtQuick 2, and uses a root that is or" << Qt::endl
1365 <<
"inherits from QtQuick's Item (not a Timer, QtObject, etc)." << Qt::endl;
1370 initialSize = rootObjectSize();
1371 bool resized = q->testAttribute(Qt::WA_Resized);
1372 if ((resizeMode == QQuickWidget::SizeViewToRootObject || !resized) &&
1373 initialSize != q->size()) {
1374 q->resize(initialSize);
1389 QPlatformBackingStoreRhiConfig config(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()));
1391 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(offscreenWindow);
1398 const bool debugLayerRequested = wd->graphicsConfig.isDebugLayerEnabled();
1399 config.setDebugLayer(debugLayerRequested);
1410 QPlatformTextureList::Flags flags = QWidgetPrivate::textureListFlags();
1411 flags |= QPlatformTextureList::NeedsPremultipliedAlphaBlending;
1416
1417
1418
1419void QQuickWidget::timerEvent(QTimerEvent* e)
1422 if (!e || e->timerId() == d->resizetimer.timerId()) {
1424 d->resizetimer.stop();
1425 }
else if (e->timerId() == d->updateTimer.timerId()) {
1426 d->eventPending =
false;
1427 d->updateTimer.stop();
1428 if (d->updatePending)
1429 d->renderSceneGraph();
1434
1435
1436
1437QSize QQuickWidget::sizeHint()
const
1439 Q_D(
const QQuickWidget);
1440 QSize rootObjectSize = d->rootObjectSize();
1441 if (rootObjectSize.isEmpty()) {
1444 return rootObjectSize;
1449
1450
1451
1452
1453
1454
1455QSize QQuickWidget::initialSize()
const
1457 Q_D(
const QQuickWidget);
1458 return d->initialSize;
1462
1463
1464
1465
1466
1467QQuickItem *QQuickWidget::rootObject()
const
1469 Q_D(
const QQuickWidget);
1474
1475
1476
1477
1478void QQuickWidget::resizeEvent(QResizeEvent *e)
1481 if (d->resizeMode == SizeRootObjectToView)
1484 if (e->size().isEmpty()) {
1486 d->fakeHidden =
true;
1490 bool needsSync =
false;
1491 if (d->fakeHidden) {
1493 d->fakeHidden =
false;
1498 if (d->useSoftwareRenderer) {
1500 if (d->softwareImage.size() != size() * devicePixelRatio()) {
1501 createFramebufferObject();
1507 if (!d->outputTexture && !d->offscreenWindow->isSceneGraphInitialized())
1509 if (!d->outputTexture || d->outputTexture->pixelSize() != size() * devicePixelRatio()) {
1511 createFramebufferObject();
1517 d->initializeWithRhi();
1521 qWarning(
"QQuickWidget::resizeEvent() no QRhi");
1526 d->render(needsSync);
1530bool QQuickWidget::focusNextPrevChild(
bool next)
1534 const auto *da = QQuickWindowPrivate::get(d->offscreenWindow)->deliveryAgentPrivate();
1537 auto *currentTarget = da->focusTargetItem();
1538 Q_ASSERT(currentTarget);
1540 auto *nextTarget = QQuickItemPrivate::nextPrevItemInTabFocusChain(currentTarget, next,
false);
1543 return QWidget::focusNextPrevChild(next);
1546 const Qt::Key k = next ? Qt::Key_Tab : Qt::Key_Backtab;
1547 QKeyEvent event(QEvent::KeyPress, k, Qt::NoModifier);
1548 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, k, Qt::NoModifier);
1549 QCoreApplication::sendEvent(d->offscreenWindow, &event);
1551 QKeyEvent releaseEvent(QEvent::KeyRelease, k, Qt::NoModifier);
1552 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, k, Qt::NoModifier);
1553 QCoreApplication::sendEvent(d->offscreenWindow, &releaseEvent);
1555 return event.isAccepted();
1559void QQuickWidget::keyPressEvent(QKeyEvent *e)
1562 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, e->key(),
1565 QCoreApplication::sendEvent(d->offscreenWindow, e);
1569void QQuickWidget::keyReleaseEvent(QKeyEvent *e)
1572 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, e->key(),
1575 QCoreApplication::sendEvent(d->offscreenWindow, e);
1579void QQuickWidget::mouseMoveEvent(QMouseEvent *e)
1582 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove, e->position().x(),
1589 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1590 e->button(), e->buttons(), e->modifiers(), e->source());
1592 mappedEvent.setTimestamp(e->timestamp());
1593 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1594 e->setAccepted(mappedEvent.isAccepted());
1598void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
1601 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
1602 e->button(), e->buttons());
1606 QMouseEvent pressEvent(QEvent::MouseButtonPress, e->position(), e->position(), e->globalPosition(),
1607 e->button(), e->buttons(), e->modifiers(), e->source());
1608 pressEvent.setTimestamp(e->timestamp());
1609 QCoreApplication::sendEvent(d->offscreenWindow, &pressEvent);
1610 e->setAccepted(pressEvent.isAccepted());
1611 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1612 e->button(), e->buttons(), e->modifiers(), e->source());
1613 mappedEvent.setTimestamp(e->timestamp());
1614 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1618void QQuickWidget::showEvent(QShowEvent *)
1621 bool shouldTriggerUpdate =
true;
1623 if (!d->useSoftwareRenderer) {
1624 d->initializeWithRhi();
1626 if (d->offscreenWindow->isSceneGraphInitialized()) {
1627 shouldTriggerUpdate =
false;
1636 if (!d->eventPending && d->updatePending) {
1637 d->updatePending =
false;
1643 if (shouldTriggerUpdate)
1647 d->offscreenWindow->setVisible(
true);
1648 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1649 service->setParentWindow(d->offscreenWindow, window()->windowHandle());
1653void QQuickWidget::hideEvent(QHideEvent *)
1656 if (!d->offscreenWindow->isPersistentSceneGraph())
1657 d->invalidateRenderControl();
1659 d->offscreenWindow->setVisible(
false);
1660 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1661 service->setParentWindow(d->offscreenWindow, d->offscreenWindow);
1665void QQuickWidget::mousePressEvent(QMouseEvent *e)
1668 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, e->button(),
1671 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1672 e->button(), e->buttons(), e->modifiers(), e->source());
1673 mappedEvent.setTimestamp(e->timestamp());
1674 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1675 e->setAccepted(mappedEvent.isAccepted());
1679void QQuickWidget::mouseReleaseEvent(QMouseEvent *e)
1682 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, e->button(),
1685 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1686 e->button(), e->buttons(), e->modifiers(), e->source());
1687 mappedEvent.setTimestamp(e->timestamp());
1688 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1689 e->setAccepted(mappedEvent.isAccepted());
1692#if QT_CONFIG(wheelevent)
1694void QQuickWidget::wheelEvent(QWheelEvent *e)
1697 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel,
1698 e->angleDelta().x(), e->angleDelta().y());
1701 QCoreApplication::sendEvent(d->offscreenWindow, e);
1706
1707
1708void QQuickWidget::focusInEvent(QFocusEvent * event)
1712 using FocusTarget = QWindowPrivate::FocusTarget;
1713 const Qt::FocusReason reason = event->reason();
1719 case Qt::TabFocusReason:
1720 case Qt::BacktabFocusReason: {
1721 const bool forward = reason == Qt::FocusReason::TabFocusReason;
1722 const FocusTarget target = forward ? FocusTarget::First : FocusTarget::Last;
1723 QQuickWindowPrivate::get(d->offscreenWindow)->setFocusToTarget(target, reason);
1729 d->offscreenWindow->focusInEvent(event);
1733
1734
1735void QQuickWidget::focusOutEvent(QFocusEvent * event)
1738 d->offscreenWindow->focusOutEvent(event);
1744 if (states & Qt::WindowMinimized)
1745 return Qt::WindowMinimized;
1746 if (states & Qt::WindowMaximized)
1747 return Qt::WindowMaximized;
1748 if (states & Qt::WindowFullScreen)
1749 return Qt::WindowFullScreen;
1752 return Qt::WindowNoState;
1757 auto item = qobject_cast<QQuickItem *>(object);
1762 for (
auto query : {Qt::ImCursorRectangle, Qt::ImAnchorRectangle, Qt::ImInputItemClipRectangle}) {
1763 if (e->queries() & query) {
1764 auto value = e->value(query);
1765 if (value.canConvert<QRectF>())
1766 e->setValue(query, item->mapRectToScene(value.toRectF()));
1770 if (e->queries() & Qt::ImCursorPosition) {
1771 auto value = e->value(Qt::ImCursorPosition);
1772 if (value.canConvert<QPointF>())
1773 e->setValue(Qt::ImCursorPosition, item->mapToScene(value.toPointF()));
1778bool QQuickWidget::event(QEvent *e)
1782 switch (e->type()) {
1785 case QEvent::TouchBegin:
1786 case QEvent::TouchEnd:
1787 case QEvent::TouchUpdate:
1788 case QEvent::TouchCancel: {
1790 bool res = QCoreApplication::sendEvent(d->offscreenWindow, e);
1791 if (e->isAccepted() && e->type() == QEvent::TouchBegin) {
1796 QPointerEvent *pointerEvent =
static_cast<QPointerEvent *>(e);
1797 auto deliveredPoints = pointerEvent->points();
1798 for (
auto &point : deliveredPoints) {
1799 if (pointerEvent->exclusiveGrabber(point) || !pointerEvent->passiveGrabbers(point).isEmpty())
1800 point.setAccepted(
true);
1806 case QEvent::FocusAboutToChange:
1807 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1809 case QEvent::InputMethod:
1810 return QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1811 case QEvent::InputMethodQuery:
1813 bool eventResult = QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1818 remapInputMethodQueryEvent(d->offscreenWindow->focusObject(),
static_cast<QInputMethodQueryEvent *>(e));
1822 case QEvent::WindowAboutToChangeInternal:
1824 d->rhi->removeCleanupCallback(
this);
1825 d->invalidateRenderControl();
1826 d->deviceLost =
true;
1830 case QEvent::WindowChangeInternal:
1831 d->handleWindowChange();
1834 case QEvent::ScreenChangeInternal:
1836 QScreen *newScreen = screen();
1837 if (d->offscreenWindow)
1838 d->offscreenWindow->setScreen(newScreen);
1841 case QEvent::DevicePixelRatioChange:
1842 if (d->useSoftwareRenderer || d->outputTexture) {
1845 createFramebufferObject();
1848 if (d->offscreenWindow) {
1849 QEvent dprChangeEvent(QEvent::DevicePixelRatioChange);
1850 QGuiApplication::sendEvent(d->offscreenWindow, &dprChangeEvent);
1855 d->updatePosition();
1858 case QEvent::WindowStateChange:
1859 d->offscreenWindow->setWindowState(resolveWindowState(windowState()));
1862 case QEvent::ShortcutOverride:
1863 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1865 case QEvent::Enter: {
1866 QEnterEvent *enterEvent =
static_cast<QEnterEvent *>(e);
1867 QEnterEvent mappedEvent(enterEvent->position(), enterEvent->scenePosition(),
1868 enterEvent->globalPosition());
1869 const bool ret = QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1870 e->setAccepted(mappedEvent.isAccepted());
1877 return QWidget::event(e);
1880#if QT_CONFIG(quick_draganddrop)
1883void QQuickWidget::dragEnterEvent(QDragEnterEvent *e)
1888 d->offscreenWindow->event(e);
1893void QQuickWidget::dragMoveEvent(QDragMoveEvent *e)
1898 d->offscreenWindow->event(e);
1902void QQuickWidget::dragLeaveEvent(QDragLeaveEvent *e)
1905 d->offscreenWindow->event(e);
1909void QQuickWidget::dropEvent(QDropEvent *e)
1912 d->offscreenWindow->event(e);
1920void QQuickWidget::triggerUpdate()
1923 d->updatePending =
true;
1924 if (!d->eventPending) {
1933 const int exhaustDelay = 5;
1934 d->updateTimer.start(exhaustDelay, Qt::PreciseTimer,
this);
1935 d->eventPending =
true;
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950void QQuickWidget::setFormat(
const QSurfaceFormat &format)
1953 QSurfaceFormat currentFormat = d->offscreenWindow->format();
1954 QSurfaceFormat newFormat = format;
1955 newFormat.setDepthBufferSize(qMax(newFormat.depthBufferSize(), currentFormat.depthBufferSize()));
1956 newFormat.setStencilBufferSize(qMax(newFormat.stencilBufferSize(), currentFormat.stencilBufferSize()));
1957 newFormat.setAlphaBufferSize(qMax(newFormat.alphaBufferSize(), currentFormat.alphaBufferSize()));
1963 d->requestedSamples = newFormat.samples();
1964 newFormat.setSamples(0);
1966 d->offscreenWindow->setFormat(newFormat);
1970
1971
1972
1973
1974
1975
1976QSurfaceFormat QQuickWidget::format()
const
1978 Q_D(
const QQuickWidget);
1979 return d->offscreenWindow->format();
1983
1984
1985
1986
1987QImage QQuickWidget::grabFramebuffer()
const
1989 return const_cast<QQuickWidgetPrivate *>(d_func())->grabFramebuffer();
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002void QQuickWidget::setClearColor(
const QColor &color)
2005 d->offscreenWindow->setColor(color);
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026QQuickWindow *QQuickWidget::quickWindow()
const
2028 Q_D(
const QQuickWidget);
2029 return d->offscreenWindow;
2033
2034
2035void QQuickWidget::paintEvent(QPaintEvent *event)
2038 if (d->useSoftwareRenderer) {
2039 QPainter painter(
this);
2040 d->updateRegion = d->updateRegion.united(event->region());
2041 if (d->updateRegion.isNull()) {
2043 painter.drawImage(rect(), d->softwareImage);
2045 QTransform transform;
2046 transform.scale(devicePixelRatio(), devicePixelRatio());
2048 QRegion targetRegion;
2049 d->updateRegion.swap(targetRegion);
2050 for (
auto targetRect : targetRegion) {
2051 auto sourceRect = transform.mapRect(QRectF(targetRect));
2052 painter.drawImage(targetRect, d->softwareImage, sourceRect);
2058void QQuickWidget::propagateFocusObjectChanged(QObject *focusObject)
2061 if (QApplication::focusObject() !=
this)
2063 if (QWindow *window = d->windowHandle(QWidgetPrivate::WindowHandleMode::TopLevel))
2064 emit window->focusObjectChanged(focusObject);
2069#include "moc_qquickwidget_p.cpp"
2071#include "moc_qquickwidget.cpp"