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 rhi->removeCleanupCallback(q);
270 if (offscreenWindow->isPersistentSceneGraph()
271 && qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)
272 && rhiConfig().api() == QPlatformBackingStoreRhiConfig::OpenGL)
283 QScopedPointer<QQuickWindow> oldOffScreenWindow(offscreenWindow);
284 offscreenWindow =
nullptr;
287 renderControl =
new QQuickWidgetRenderControl(q);
290 if (oldOffScreenWindow)
291 offscreenWindow->setColor(oldOffScreenWindow->color());
293 QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
294 QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
296 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(root))
297 sgItem->setParentItem(offscreenWindow->contentItem());
303 , offscreenWindow(
nullptr)
311 , resizeMode(QQuickWidget::SizeViewToRootObject)
341 q->destroyFramebufferObject();
342 delete offscreenWindow;
344 offscreenRenderer.reset();
352 if (!source.isEmpty()) {
353 component =
new QQmlComponent(engine.data(), source, q);
355 q->continueExecute();
357 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
358 q, SLOT(continueExecute()));
368 component =
new QQmlComponent(engine.data(), uri, typeName, q);
370 q->continueExecute();
372 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
373 q, SLOT(continueExecute()));
378 const QRectF &oldGeometry)
381 if (resizeItem == root && resizeMode == QQuickWidget::SizeViewToRootObject) {
383 resizetimer.start(0,q);
385 QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, oldGeometry);
395 q->createFramebufferObject();
399 qWarning(
"QQuickWidget: Attempted to render scene with no rhi");
409 QQuickRenderControlPrivate::FrameStatus frameStatus = QQuickRenderControlPrivate::get(renderControl)->frameStatus;
410 if (frameStatus == QQuickRenderControlPrivate::DeviceLostInBeginFrame) {
417 if (frameStatus != QQuickRenderControlPrivate::RecordingFrame) {
418 qWarning(
"QQuickWidget: Failed to begin recording a frame");
436 if (!offscreenWindow)
438 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(offscreenWindow);
439 auto softwareRenderer =
static_cast<QSGSoftwareRenderer*>(cd->renderer);
440 if (softwareRenderer && !softwareImage.isNull()) {
441 softwareRenderer->setCurrentPaintDevice(&softwareImage);
443 softwareRenderer->markDirty();
448 updateRegion += softwareRenderer->flushRegion();
458 if (!q->isVisible() || fakeHidden)
463#if QT_CONFIG(graphicsview)
464 if (q->window()->graphicsProxyWidget())
465 QWidgetPrivate::nearestGraphicsProxyWidget(q)->update();
469 if (!useSoftwareRenderer)
471 else if (!updateRegion.isEmpty())
472 q->update(updateRegion);
487 QRhiCommandBuffer *cb =
nullptr;
488 rhi->beginOffscreenFrame(&cb);
489 QRhiResourceUpdateBatch *resUpd =
rhi->nextResourceUpdateBatch();
490 QRhiReadbackResult readResult;
491 resUpd->readBackTexture(QRhiReadbackDescription(
outputTexture), &readResult);
492 cb->resourceUpdate(resUpd);
493 rhi->endOffscreenFrame();
494 if (!readResult.data.isEmpty()) {
495 QImage wrapperImage(
reinterpret_cast<
const uchar *>(readResult.data.constData()),
496 readResult.pixelSize.width(), readResult.pixelSize.height(),
497 QImage::Format_RGBA8888_Premultiplied);
498 if (
rhi->isYUpInFramebuffer())
499 return wrapperImage.flipped();
501 return wrapperImage.copy();
506 return offscreenWindow->grabWindow();
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
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
641
642
643
644
645
646
647
648
649
650
651
655
656
657
660
661
662
663
664QQuickWidget::QQuickWidget(QWidget *parent)
665 : QWidget(*(
new QQuickWidgetPrivate), parent, {})
671
672
673
674
675
676QQuickWidget::QQuickWidget(
const QUrl &source, QWidget *parent)
677 : QQuickWidget(parent)
683
684
685
686
687
688
689QQuickWidget::QQuickWidget(QAnyStringView uri, QAnyStringView typeName, QWidget *parent)
690 : QQuickWidget(parent)
692 loadFromModule(uri, typeName);
696
697
698
699
700
701
702QQuickWidget::QQuickWidget(QQmlEngine* engine, QWidget *parent)
703 : QWidget(*(
new QQuickWidgetPrivate), parent, {})
705 d_func()->init(engine);
709
710
711QQuickWidget::~QQuickWidget()
720 d->rhi->removeCleanupCallback(
this);
731
732
733
734
735
736
737
738
739
742
743
744
745
746
747
748
749
750void QQuickWidget::setSource(
const QUrl& url)
758
759
760
761
762void QQuickWidget::setContent(
const QUrl& url, QQmlComponent *component, QObject* item)
766 d->component = component;
768 if (d->component && d->component->isError()) {
769 const QList<QQmlError> errorList = d->component->errors();
770 for (
const QQmlError &error : errorList) {
771 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
774 emit statusChanged(status());
778 d->setRootObject(item);
779 emit statusChanged(status());
782
783
784
785
786
787
788
789
790
791
792void QQuickWidget::setInitialProperties(
const QVariantMap &initialProperties)
795 d->initialProperties = initialProperties;
799
800
801
802
803
804
805
806
807
808
809
810
811void QQuickWidget::loadFromModule(QAnyStringView uri, QAnyStringView typeName)
815 d->execute(uri, typeName);
819
820
821
822
823QUrl QQuickWidget::source()
const
825 Q_D(
const QQuickWidget);
830
831
832
833QQmlEngine* QQuickWidget::engine()
const
835 Q_D(
const QQuickWidget);
837 return const_cast<QQmlEngine *>(d->engine.data());
841
842
843
844
845
846
847QQmlContext* QQuickWidget::rootContext()
const
849 Q_D(
const QQuickWidget);
851 return d->engine.data()->rootContext();
855
856
857
858
859
860
861
862
863
866
867
868
869
870
871
874
875
876
877
878
879
880
881
882
883
884
885
886
889
890
891
893QQuickWidget::Status QQuickWidget::status()
const
895 Q_D(
const QQuickWidget);
896 if (!d->engine && !d->source.isEmpty())
897 return QQuickWidget::Error;
900 return QQuickWidget::Null;
902 if (d->component->status() == QQmlComponent::Ready && !d->root)
903 return QQuickWidget::Error;
905 return QQuickWidget::Status(d->component->status());
909
910
911
912
913
914QList<QQmlError> QQuickWidget::errors()
const
916 Q_D(
const QQuickWidget);
917 QList<QQmlError> errs;
920 errs = d->component->errors();
922 if (!d->engine && !d->source.isEmpty()) {
924 error.setDescription(QLatin1String(
"QQuickWidget: invalid qml engine."));
927 if (d->component && d->component->status() == QQmlComponent::Ready && !d->root) {
929 error.setDescription(QLatin1String(
"QQuickWidget: invalid root object."));
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
953void QQuickWidget::setResizeMode(ResizeMode mode)
956 if (d->resizeMode == mode)
960 if (d->resizeMode == SizeViewToRootObject) {
961 QQuickItemPrivate *p = QQuickItemPrivate::get(d->root);
962 p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
966 d->resizeMode = mode;
975 if (resizeMode == QQuickWidget::SizeViewToRootObject) {
976 QQuickItemPrivate *p = QQuickItemPrivate::get(root);
977 p->addItemChangeListener(
this, QQuickItemPrivate::Geometry);
989 if (resizeMode == QQuickWidget::SizeViewToRootObject) {
990 QSize newSize = QSize(root->width(), root->height());
991 if (newSize.isValid()) {
992 if (newSize != q->size()) {
995 }
else if (offscreenWindow->size().isEmpty()) {
998 offscreenWindow->resize(newSize);
999 offscreenWindow->contentItem()->setSize(newSize);
1002 }
else if (resizeMode == QQuickWidget::SizeRootObjectToView) {
1003 const bool needToUpdateWidth = !qFuzzyCompare(q->width(), root->width());
1004 const bool needToUpdateHeight = !qFuzzyCompare(q->height(), root->height());
1006 if (needToUpdateWidth && needToUpdateHeight) {
1011 const QSizeF newSize(q->width(), q->height());
1012 offscreenWindow->resize(newSize.toSize());
1013 offscreenWindow->contentItem()->setSize(newSize);
1014 root->setSize(newSize);
1015 }
else if (needToUpdateWidth) {
1016 const int newWidth = q->width();
1017 offscreenWindow->setWidth(newWidth);
1018 offscreenWindow->contentItem()->setWidth(newWidth);
1019 root->setWidth(newWidth);
1020 }
else if (needToUpdateHeight) {
1021 const int newHeight = q->height();
1022 offscreenWindow->setHeight(newHeight);
1023 offscreenWindow->contentItem()->setHeight(newHeight);
1024 root->setHeight(newHeight);
1030
1031
1032
1033
1037 if (offscreenWindow ==
nullptr)
1040 const QPoint &pos = q->mapToGlobal(QPoint(0, 0));
1041 if (offscreenWindow->position() != pos)
1042 offscreenWindow->setPosition(pos);
1047 QSize rootObjectSize(0,0);
1048 int widthCandidate = -1;
1049 int heightCandidate = -1;
1051 widthCandidate = root->width();
1052 heightCandidate = root->height();
1054 if (widthCandidate > 0) {
1055 rootObjectSize.setWidth(widthCandidate);
1057 if (heightCandidate > 0) {
1058 rootObjectSize.setHeight(heightCandidate);
1060 return rootObjectSize;
1067 QString translatedMessage;
1068 QString untranslatedMessage;
1069 QQuickWindowPrivate::rhiCreationFailureMessage(QLatin1String(
"QRhi"), &translatedMessage, &untranslatedMessage);
1071 static const QMetaMethod errorSignal = QMetaMethod::fromSignal(&QQuickWidget::sceneGraphError);
1072 const bool signalConnected = q->isSignalConnected(errorSignal);
1073 if (signalConnected)
1074 emit q->sceneGraphError(QQuickWindow::ContextNotAvailable, translatedMessage);
1076#if defined(Q_OS_WIN) && QT_CONFIG(messagebox)
1077 if (!signalConnected && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow())
1078 QMessageBox::critical(q, QCoreApplication::applicationName(), translatedMessage);
1080 if (!signalConnected)
1081 qFatal(
"%s", qPrintable(untranslatedMessage));
1087 case QSGRendererInterface::OpenGL:
1088 return QPlatformBackingStoreRhiConfig::OpenGL;
1089 case QSGRendererInterface::Vulkan:
1090 return QPlatformBackingStoreRhiConfig::Vulkan;
1091 case QSGRendererInterface::Direct3D11:
1092 return QPlatformBackingStoreRhiConfig::D3D11;
1093 case QSGRendererInterface::Direct3D12:
1094 return QPlatformBackingStoreRhiConfig::D3D12;
1095 case QSGRendererInterface::Metal:
1096 return QPlatformBackingStoreRhiConfig::Metal;
1098 return QPlatformBackingStoreRhiConfig::Null;
1109 QRhi *backingStoreRhi = QWidgetPrivate::rhi();
1110 if (backingStoreRhi &&
rhi != backingStoreRhi) {
1114 if (rhi == offscreenRenderer.rhi()) {
1125 const bool onlyNeedsSgInit = rhi && !offscreenWindow->isSceneGraphInitialized();
1127 if (!onlyNeedsSgInit) {
1131 if (QRhi *backingStoreRhi = QWidgetPrivate::rhi()) {
1132 rhi = backingStoreRhi;
1134 rhi->addCleanupCallback(q, [
this](QRhi *rhi) {
1135 if (
this->rhi == rhi) {
1138 this->rhi =
nullptr;
1149 offscreenRenderer.setConfig(rhiConfig());
1150 offscreenRenderer.setFormat(q->format());
1152 if (offscreenRenderer.create())
1153 rhi = offscreenRenderer.rhi();
1158 if (rhi && rhi->backend() != QBackingStoreRhiSupport::apiToRhiBackend(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()))) {
1159 qWarning(
"The top-level window is not using the expected graphics API for composition, "
1160 "'%s' is not compatible with this QQuickWidget",
1161 rhi->backendName());
1167 if (!offscreenWindow->isSceneGraphInitialized()) {
1168 offscreenWindow->setGraphicsDevice(QQuickGraphicsDevice::fromRhi(rhi));
1169#if QT_CONFIG(vulkan)
1170 if (QWindow *w = q->window()->windowHandle())
1171 offscreenWindow->setVulkanInstance(w->vulkanInstance());
1172 else if (rhi == offscreenRenderer.rhi())
1173 offscreenWindow->setVulkanInstance(QVulkanDefaultInstance::instance());
1178 qWarning(
"QQuickWidget: Failed to get a QRhi from the top-level widget's window");
1182void QQuickWidget::createFramebufferObject()
1188 if (size().isEmpty())
1194 const QPoint &globalPos = mapToGlobal(QPoint(0, 0));
1195 d->offscreenWindow->setGeometry(globalPos.x(), globalPos.y(), width(), height());
1196 d->offscreenWindow->contentItem()->setSize(QSizeF(width(), height()));
1198 if (d->useSoftwareRenderer) {
1199 const QSize imageSize = size() * devicePixelRatio();
1200 d->softwareImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
1201 d->softwareImage.setDevicePixelRatio(devicePixelRatio());
1202 d->forceFullUpdate =
true;
1207 qWarning(
"QQuickWidget: Attempted to create output texture with no QRhi");
1211 int samples = d->requestedSamples;
1212 if (d->rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer))
1213 samples = QSGRhiSupport::chooseSampleCount(samples, d->rhi);
1217 const int minTexSize = d->rhi->resourceLimit(QRhi::TextureSizeMin);
1218 const int maxTexSize = d->rhi->resourceLimit(QRhi::TextureSizeMax);
1220 QSize fboSize = size() * devicePixelRatio();
1221 if (fboSize.width() > maxTexSize || fboSize.height() > maxTexSize) {
1222 qWarning(
"QQuickWidget: Requested backing texture size is %dx%d, but the maximum texture size for the 3D API implementation is %dx%d",
1223 fboSize.width(), fboSize.height(),
1224 maxTexSize, maxTexSize);
1226 fboSize.setWidth(qMin(maxTexSize, qMax(minTexSize, fboSize.width())));
1227 fboSize.setHeight(qMin(maxTexSize, qMax(minTexSize, fboSize.height())));
1230 if (!d->outputTexture) {
1231 d->outputTexture = d->rhi->newTexture(QRhiTexture::RGBA8, fboSize, 1, QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
1232 if (!d->outputTexture->create()) {
1233 qWarning(
"QQuickWidget: failed to create output texture of size %dx%d",
1234 fboSize.width(), fboSize.height());
1237 if (!d->depthStencil) {
1238 d->depthStencil = d->rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, fboSize, samples);
1239 if (!d->depthStencil->create()) {
1240 qWarning(
"QQuickWidget: failed to create depth/stencil buffer of size %dx%d and sample count %d",
1241 fboSize.width(), fboSize.height(), samples);
1244 if (samples > 1 && !d->msaaBuffer) {
1245 d->msaaBuffer = d->rhi->newRenderBuffer(QRhiRenderBuffer::Color, fboSize, samples);
1246 if (!d->msaaBuffer->create()) {
1247 qWarning(
"QQuickWidget: failed to create multisample renderbuffer of size %dx%d and sample count %d",
1248 fboSize.width(), fboSize.height(), samples);
1252 QRhiTextureRenderTargetDescription rtDesc;
1253 QRhiColorAttachment colorAtt;
1255 colorAtt.setTexture(d->outputTexture);
1257 colorAtt.setRenderBuffer(d->msaaBuffer);
1258 colorAtt.setResolveTexture(d->outputTexture);
1260 rtDesc.setColorAttachments({ colorAtt });
1261 rtDesc.setDepthStencilBuffer(d->depthStencil);
1262 d->rt = d->rhi->newTextureRenderTarget(rtDesc);
1263 d->rtRp = d->rt->newCompatibleRenderPassDescriptor();
1264 d->rt->setRenderPassDescriptor(d->rtRp);
1267 if (d->outputTexture->pixelSize() != fboSize) {
1268 d->outputTexture->setPixelSize(fboSize);
1269 if (!d->outputTexture->create()) {
1270 qWarning(
"QQuickWidget: failed to create resized output texture of size %dx%d",
1271 fboSize.width(), fboSize.height());
1273 d->depthStencil->setPixelSize(fboSize);
1274 if (!d->depthStencil->create()) {
1275 qWarning(
"QQuickWidget: failed to create resized depth/stencil buffer of size %dx%d",
1276 fboSize.width(), fboSize.height());
1278 if (d->msaaBuffer) {
1279 d->msaaBuffer->setPixelSize(fboSize);
1280 if (!d->msaaBuffer->create()) {
1281 qWarning(
"QQuickWidget: failed to create resized multisample renderbuffer of size %dx%d",
1282 fboSize.width(), fboSize.height());
1287 d->offscreenWindow->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(d->rt));
1289 d->renderControl->setSamples(samples);
1294 Q_ASSERT(!d->offscreenWindow->handle());
1297void QQuickWidget::destroyFramebufferObject()
1301 if (d->useSoftwareRenderer) {
1302 d->softwareImage = QImage();
1310 delete d->depthStencil;
1311 d->depthStencil =
nullptr;
1312 delete d->msaaBuffer;
1313 d->msaaBuffer =
nullptr;
1314 delete d->outputTexture;
1315 d->outputTexture =
nullptr;
1318QQuickWidget::ResizeMode QQuickWidget::resizeMode()
const
1320 Q_D(
const QQuickWidget);
1321 return d->resizeMode;
1325
1326
1327void QQuickWidget::continueExecute()
1330 disconnect(d->component, SIGNAL(statusChanged(QQmlComponent::Status)),
this, SLOT(continueExecute()));
1332 if (d->component->isError()) {
1333 const QList<QQmlError> errorList = d->component->errors();
1334 for (
const QQmlError &error : errorList) {
1335 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
1338 emit statusChanged(status());
1342 std::unique_ptr<QObject> obj(d->initialProperties.empty()
1343 ? d->component->create()
1344 : d->component->createWithInitialProperties(d->initialProperties));
1346 if (d->component->isError()) {
1347 const QList<QQmlError> errorList = d->component->errors();
1348 for (
const QQmlError &error : errorList) {
1349 QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr).warning()
1352 emit statusChanged(status());
1358 if (d->source.isEmpty())
1359 d->source = d->component->url();
1361 d->setRootObject(obj.release());
1362 emit statusChanged(status());
1366
1367
1374 if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
1376 sgItem->setParentItem(offscreenWindow->contentItem());
1377 }
else if (qobject_cast<QWindow *>(obj)) {
1378 qWarning() <<
"QQuickWidget does not support using windows as a root item." << Qt::endl
1380 <<
"If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << Qt::endl;
1382 qWarning() <<
"QQuickWidget only supports loading of root objects that derive from QQuickItem." << Qt::endl
1384 <<
"Ensure your QML code is written for QtQuick 2, and uses a root that is or" << Qt::endl
1385 <<
"inherits from QtQuick's Item (not a Timer, QtObject, etc)." << Qt::endl;
1390 initialSize = rootObjectSize();
1391 bool resized = q->testAttribute(Qt::WA_Resized);
1392 if ((resizeMode == QQuickWidget::SizeViewToRootObject || !resized) &&
1393 initialSize != q->size()) {
1394 q->resize(initialSize);
1409 QPlatformBackingStoreRhiConfig config(graphicsApiToBackingStoreRhiApi(QQuickWindow::graphicsApi()));
1411 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(offscreenWindow);
1418 const bool debugLayerRequested = wd->graphicsConfig.isDebugLayerEnabled();
1419 config.setDebugLayer(debugLayerRequested);
1430 QPlatformTextureList::Flags flags = QWidgetPrivate::textureListFlags();
1431 flags |= QPlatformTextureList::NeedsPremultipliedAlphaBlending;
1436
1437
1438
1439void QQuickWidget::timerEvent(QTimerEvent* e)
1442 if (!e || e->timerId() == d->resizetimer.timerId()) {
1444 d->resizetimer.stop();
1445 }
else if (e->timerId() == d->updateTimer.timerId()) {
1446 d->eventPending =
false;
1447 d->updateTimer.stop();
1448 if (d->updatePending)
1449 d->renderSceneGraph();
1454
1455
1456
1457QSize QQuickWidget::sizeHint()
const
1459 Q_D(
const QQuickWidget);
1460 QSize rootObjectSize = d->rootObjectSize();
1461 if (rootObjectSize.isEmpty()) {
1464 return rootObjectSize;
1469
1470
1471
1472
1473
1474
1475QSize QQuickWidget::initialSize()
const
1477 Q_D(
const QQuickWidget);
1478 return d->initialSize;
1482
1483
1484
1485
1486
1487QQuickItem *QQuickWidget::rootObject()
const
1489 Q_D(
const QQuickWidget);
1494
1495
1496
1497
1498void QQuickWidget::resizeEvent(QResizeEvent *e)
1501 if (d->resizeMode == SizeRootObjectToView)
1504 if (e->size().isEmpty()) {
1506 d->fakeHidden =
true;
1510 bool needsSync =
false;
1511 if (d->fakeHidden) {
1513 d->fakeHidden =
false;
1518 if (d->useSoftwareRenderer) {
1520 if (d->softwareImage.size() != size() * devicePixelRatio()) {
1521 createFramebufferObject();
1527 if (!d->outputTexture && !d->offscreenWindow->isSceneGraphInitialized())
1529 if (!d->outputTexture || d->outputTexture->pixelSize() != size() * devicePixelRatio()) {
1531 createFramebufferObject();
1537 d->initializeWithRhi();
1541 qWarning(
"QQuickWidget::resizeEvent() no QRhi");
1546 d->render(needsSync);
1550bool QQuickWidget::focusNextPrevChild(
bool next)
1554 const auto *da = QQuickWindowPrivate::get(d->offscreenWindow)->deliveryAgentPrivate();
1557 auto *currentTarget = da->focusTargetItem();
1558 Q_ASSERT(currentTarget);
1560 auto *nextTarget = QQuickItemPrivate::nextPrevItemInTabFocusChain(currentTarget, next,
false);
1563 return QWidget::focusNextPrevChild(next);
1566 const Qt::Key k = next ? Qt::Key_Tab : Qt::Key_Backtab;
1567 QKeyEvent event(QEvent::KeyPress, k, Qt::NoModifier);
1568 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, k, Qt::NoModifier);
1569 QCoreApplication::sendEvent(d->offscreenWindow, &event);
1571 QKeyEvent releaseEvent(QEvent::KeyRelease, k, Qt::NoModifier);
1572 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, k, Qt::NoModifier);
1573 QCoreApplication::sendEvent(d->offscreenWindow, &releaseEvent);
1575 return event.isAccepted();
1579void QQuickWidget::keyPressEvent(QKeyEvent *e)
1582 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, e->key(),
1585 QCoreApplication::sendEvent(d->offscreenWindow, e);
1589void QQuickWidget::keyReleaseEvent(QKeyEvent *e)
1592 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, e->key(),
1595 QCoreApplication::sendEvent(d->offscreenWindow, e);
1599void QQuickWidget::mouseMoveEvent(QMouseEvent *e)
1602 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove, e->position().x(),
1609 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1610 e->button(), e->buttons(), e->modifiers(), e->source());
1612 mappedEvent.setTimestamp(e->timestamp());
1613 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1614 e->setAccepted(mappedEvent.isAccepted());
1618void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
1621 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
1622 e->button(), e->buttons());
1626 QMouseEvent pressEvent(QEvent::MouseButtonPress, e->position(), e->position(), e->globalPosition(),
1627 e->button(), e->buttons(), e->modifiers(), e->source());
1628 pressEvent.setTimestamp(e->timestamp());
1629 QCoreApplication::sendEvent(d->offscreenWindow, &pressEvent);
1630 e->setAccepted(pressEvent.isAccepted());
1631 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1632 e->button(), e->buttons(), e->modifiers(), e->source());
1633 mappedEvent.setTimestamp(e->timestamp());
1634 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1638void QQuickWidget::showEvent(QShowEvent *)
1641 bool shouldTriggerUpdate =
true;
1643 if (!d->useSoftwareRenderer) {
1644 d->initializeWithRhi();
1646 if (d->offscreenWindow->isSceneGraphInitialized()) {
1647 shouldTriggerUpdate =
false;
1656 if (!d->eventPending && d->updatePending) {
1657 d->updatePending =
false;
1663 if (shouldTriggerUpdate)
1667 d->offscreenWindow->setVisible(
true);
1668 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1669 service->setParentWindow(d->offscreenWindow, window()->windowHandle());
1673void QQuickWidget::hideEvent(QHideEvent *)
1676 if (!d->offscreenWindow->isPersistentSceneGraph())
1677 d->invalidateRenderControl();
1679 d->offscreenWindow->setVisible(
false);
1680 if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
1681 service->setParentWindow(d->offscreenWindow, d->offscreenWindow);
1685void QQuickWidget::mousePressEvent(QMouseEvent *e)
1688 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, e->button(),
1691 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1692 e->button(), e->buttons(), e->modifiers(), e->source());
1693 mappedEvent.setTimestamp(e->timestamp());
1694 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1695 e->setAccepted(mappedEvent.isAccepted());
1699void QQuickWidget::mouseReleaseEvent(QMouseEvent *e)
1702 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, e->button(),
1705 QMouseEvent mappedEvent(e->type(), e->position(), e->position(), e->globalPosition(),
1706 e->button(), e->buttons(), e->modifiers(), e->source());
1707 mappedEvent.setTimestamp(e->timestamp());
1708 QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1709 e->setAccepted(mappedEvent.isAccepted());
1712#if QT_CONFIG(wheelevent)
1714void QQuickWidget::wheelEvent(QWheelEvent *e)
1717 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel,
1718 e->angleDelta().x(), e->angleDelta().y());
1721 QCoreApplication::sendEvent(d->offscreenWindow, e);
1726
1727
1728void QQuickWidget::focusInEvent(QFocusEvent * event)
1732 using FocusTarget = QWindowPrivate::FocusTarget;
1733 const Qt::FocusReason reason = event->reason();
1739 case Qt::TabFocusReason:
1740 case Qt::BacktabFocusReason: {
1741 const bool forward = reason == Qt::FocusReason::TabFocusReason;
1742 const FocusTarget target = forward ? FocusTarget::First : FocusTarget::Last;
1743 QQuickWindowPrivate::get(d->offscreenWindow)->setFocusToTarget(target, reason);
1749 d->offscreenWindow->focusInEvent(event);
1753
1754
1755void QQuickWidget::focusOutEvent(QFocusEvent * event)
1758 d->offscreenWindow->focusOutEvent(event);
1764 if (states & Qt::WindowMinimized)
1765 return Qt::WindowMinimized;
1766 if (states & Qt::WindowMaximized)
1767 return Qt::WindowMaximized;
1768 if (states & Qt::WindowFullScreen)
1769 return Qt::WindowFullScreen;
1772 return Qt::WindowNoState;
1777 auto item = qobject_cast<QQuickItem *>(object);
1782 for (
auto query : {Qt::ImCursorRectangle, Qt::ImAnchorRectangle, Qt::ImInputItemClipRectangle}) {
1783 if (e->queries() & query) {
1784 auto value = e->value(query);
1785 if (value.canConvert<QRectF>())
1786 e->setValue(query, item->mapRectToScene(value.toRectF()));
1790 if (e->queries() & Qt::ImCursorPosition) {
1791 auto value = e->value(Qt::ImCursorPosition);
1792 if (value.canConvert<QPointF>())
1793 e->setValue(Qt::ImCursorPosition, item->mapToScene(value.toPointF()));
1798bool QQuickWidget::event(QEvent *e)
1802 switch (e->type()) {
1805 case QEvent::TouchBegin:
1806 case QEvent::TouchEnd:
1807 case QEvent::TouchUpdate:
1808 case QEvent::TouchCancel: {
1810 bool res = QCoreApplication::sendEvent(d->offscreenWindow, e);
1811 if (e->isAccepted() && e->type() == QEvent::TouchBegin) {
1816 QPointerEvent *pointerEvent =
static_cast<QPointerEvent *>(e);
1817 auto deliveredPoints = pointerEvent->points();
1818 for (
auto &point : deliveredPoints) {
1819 if (pointerEvent->exclusiveGrabber(point) || !pointerEvent->passiveGrabbers(point).isEmpty())
1820 point.setAccepted(
true);
1826 case QEvent::FocusAboutToChange:
1827 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1829 case QEvent::InputMethod:
1830 return QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1831 case QEvent::InputMethodQuery:
1833 bool eventResult = QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
1838 remapInputMethodQueryEvent(d->offscreenWindow->focusObject(),
static_cast<QInputMethodQueryEvent *>(e));
1842 case QEvent::WindowAboutToChangeInternal:
1843 d->handleWindowAboutToChange();
1846 case QEvent::WindowChangeInternal:
1847 d->handleWindowChange();
1850 case QEvent::ScreenChangeInternal:
1852 QScreen *newScreen = screen();
1853 if (d->offscreenWindow)
1854 d->offscreenWindow->setScreen(newScreen);
1857 case QEvent::DevicePixelRatioChange:
1858 if (d->useSoftwareRenderer || d->outputTexture) {
1861 createFramebufferObject();
1864 if (d->offscreenWindow) {
1865 QEvent dprChangeEvent(QEvent::DevicePixelRatioChange);
1866 QGuiApplication::sendEvent(d->offscreenWindow, &dprChangeEvent);
1871 d->updatePosition();
1874 case QEvent::WindowStateChange:
1875 d->offscreenWindow->setWindowState(resolveWindowState(windowState()));
1878 case QEvent::ShortcutOverride:
1879 return QCoreApplication::sendEvent(d->offscreenWindow, e);
1881 case QEvent::Enter: {
1882 QEnterEvent *enterEvent =
static_cast<QEnterEvent *>(e);
1883 QEnterEvent mappedEvent(enterEvent->position(), enterEvent->scenePosition(),
1884 enterEvent->globalPosition());
1885 const bool ret = QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
1886 e->setAccepted(mappedEvent.isAccepted());
1893 return QWidget::event(e);
1896#if QT_CONFIG(quick_draganddrop)
1899void QQuickWidget::dragEnterEvent(QDragEnterEvent *e)
1904 d->offscreenWindow->event(e);
1909void QQuickWidget::dragMoveEvent(QDragMoveEvent *e)
1914 d->offscreenWindow->event(e);
1918void QQuickWidget::dragLeaveEvent(QDragLeaveEvent *e)
1921 d->offscreenWindow->event(e);
1925void QQuickWidget::dropEvent(QDropEvent *e)
1928 d->offscreenWindow->event(e);
1936void QQuickWidget::triggerUpdate()
1939 d->updatePending =
true;
1940 if (!d->eventPending) {
1949 const int exhaustDelay = 5;
1950 d->updateTimer.start(exhaustDelay, Qt::PreciseTimer,
this);
1951 d->eventPending =
true;
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966void QQuickWidget::setFormat(
const QSurfaceFormat &format)
1969 QSurfaceFormat currentFormat = d->offscreenWindow->format();
1970 QSurfaceFormat newFormat = format;
1971 newFormat.setDepthBufferSize(qMax(newFormat.depthBufferSize(), currentFormat.depthBufferSize()));
1972 newFormat.setStencilBufferSize(qMax(newFormat.stencilBufferSize(), currentFormat.stencilBufferSize()));
1973 newFormat.setAlphaBufferSize(qMax(newFormat.alphaBufferSize(), currentFormat.alphaBufferSize()));
1979 d->requestedSamples = newFormat.samples();
1980 newFormat.setSamples(0);
1982 d->offscreenWindow->setFormat(newFormat);
1986
1987
1988
1989
1990
1991
1992QSurfaceFormat QQuickWidget::format()
const
1994 Q_D(
const QQuickWidget);
1995 return d->offscreenWindow->format();
1999
2000
2001
2002
2003QImage QQuickWidget::grabFramebuffer()
const
2005 return const_cast<QQuickWidgetPrivate *>(d_func())->grabFramebuffer();
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018void QQuickWidget::setClearColor(
const QColor &color)
2021 d->offscreenWindow->setColor(color);
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042QQuickWindow *QQuickWidget::quickWindow()
const
2044 Q_D(
const QQuickWidget);
2045 return d->offscreenWindow;
2049
2050
2051void QQuickWidget::paintEvent(QPaintEvent *event)
2054 if (d->useSoftwareRenderer) {
2055 QPainter painter(
this);
2056 d->updateRegion = d->updateRegion.united(event->region());
2057 if (d->updateRegion.isNull()) {
2059 painter.drawImage(rect(), d->softwareImage);
2061 QTransform transform;
2062 transform.scale(devicePixelRatio(), devicePixelRatio());
2064 QRegion targetRegion;
2065 d->updateRegion.swap(targetRegion);
2066 for (
auto targetRect : targetRegion) {
2067 auto sourceRect = transform.mapRect(QRectF(targetRect));
2068 painter.drawImage(targetRect, d->softwareImage, sourceRect);
2074void QQuickWidget::propagateFocusObjectChanged(QObject *focusObject)
2077 if (QApplication::focusObject() !=
this)
2079 if (QWindow *window = d->windowHandle(QWidgetPrivate::WindowHandleMode::TopLevel))
2080 emit window->focusObjectChanged(focusObject);
2085#include "moc_qquickwidget_p.cpp"
2087#include "moc_qquickwidget.cpp"